开发艺术探索 设计模式 个人读书笔记

2017-05-10  本文已影响46人  劳达斯

Activity

IPC

跟着书走了一遍,还是有点蒙,想要真正掌握这个点,我想还是需要实际项目的经验。初步认识了Binder。Binder指的是一种跨进程通信方式,比如说AIDL使用Binder进行通信,指的就是这种IPC机制。

对于开发人员来讲,Binder是Android中的一个可以帮助你进行跨进程通信的类,是客户端和服务端进行通信的媒介。Binder驱动会对Binder对象进行特殊处理,帮助你完成数据的转换。

(服务端实现的Binder对象返回一个代理对象到客户端,客户端对这个代理Binder对象进行操作,会通过Binder驱动转发到服务端的本地Binder对象上去。Binder驱动会对这个对象进行特殊处理,帮助你完成数据的转换)

在安卓framework层中,ServiceManager通过Binder连接了各种Manager,比如WindowManager、ActivityManager等等。。。android中常用的实现IPC的方式,Bundle,文件共享,AIDL,Messenger,CP、Socket。

View

View的属性top、left、right、bottom,x、y,translationX、translationY。

x,y是View的左上角坐标,换算关系如下:

x = left + translationX ;

y = top + translationY ;

view在平移的过程中,改变的是x、y、translationX、translationY这四个属性,t、l、r、b不会发生改变,这四个属性在onLayout()之后就确定了。

动画

Window和WindowManager

Android中的消息机制

随便记,不涉及原理。

Android中的多线程

除了在java的多线程知识,在android中,还需要了解在android在Thread的基础上封装的几个类,AsyncTask、HandlerThead、IntentService。

以上就是主要的参数,还有一些不常用参数未列出。

Android中常见的四类具有不同功能特性的线程池,他们都直接或间接地通过配置ThreadPoolExecutor来实现自己的功能特性。

  1. FixedThreadPool:通过Executors的newFixedThreadPool(int nThreads)来创建。它是一种线程数量固定的线程池。
  2. CachedThreadPool:一种县城数量不定的线程池,它只有非核心线程,并且最大线程数为Integer.MAX_VALUE。线程超时时间为60秒,超时则会被回收。这个线程池比较适合执行大量的耗时较少的任务。当线程池处于闲置状态时,所有线程都会被超时回收,和上面的FixedThreadPool不一样。
  3. ScheduledThreadPool:这个线程池的核心线程数固定,最大线程数没有限制。并且当非核心线程闲置时会被立即回收。这类线程池主要用于执行定时任务和具有固定周期的重复任务。
  4. SingleThreadExecutor:这类线程池内部只有一个核心线程,它确保所有的任务都在同一个线程中按顺序执行。SingleThreadExecutor的意义在于统一所有的外界任务到一个线程中去执行。所以在线程同步问题上不需要去过多地去考虑。

对了,这两年出现了一个特别牛B的库:RxJava。异步、简洁的链式调用。这个Cool得不行的响应式编程框架一用根本停不下来,没用过的可以去试试!

Bitmap和Cache

我看过google出品的图片加载框架gilde的代码总体架构,只能说惊了。过一段时间我会动手写一个ImageLoader来练手。。。以熟悉设计模式、网络请求、内存优化以及上边的知识点等等。加油加油。

综合技术

JNI和NDK编程

Android性能优化

其实不仅是onDraw,在onMeasure和onLayout中也要尽量注意。优化我们的算法逻辑。以提高性能。

待完善。。。

设计模式 个人笔记

面向对象六大原则

设计模式

单例模式

单例模式就不用过多的介绍了。下面列两种推荐写法:

在第一次调用Singleton的getInstance方法时,JVM会加载SingletonHolder类,因为这一步发生在JVM,所以保证了线程安全与单例对象的唯一性,同时还有延迟加载的效果。

是的没错,就是如此的简单。枚举单例模式不仅写法简单,而且在保证了线程安全与唯一性的同时,还保证了反序列化时不会重新生成对象。可以说这种写法是目前单例模式的最佳写法。

Builder模式(建造者模式)

Builder模式的定义:将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
相对于直接在javabean里使用setter,builder模式更加易读,在调用build()方法之后才返回相应的对象,保证了对象的一致性。

public class MyBuilder{
    private int id;
    private String num;
    public MyData build(){
        MyData d=new MyData();
        d.setId(id);
        d.setNum(num);
        return t;
        //build之后返回组装好的对象。
        //在这里可以对设置数据的调用顺序进行正确的控制。
    }
    public MyBuilder setId(int id){
        this.id=id;
        return this;
    }
    //返回自身this,用于链式调用。
    public MyBuilder setNum(String num){
        this.num=num;
        return this;
    }

}

public class Test{
    public static void  main(String[] args){
        MyData d=new MyBuilder().setId(10).setNum("hc").build();
    }

 }

什么时候使用builder模式呢?

Android中的builder模式

AlertDialog.Builer builder=new AlertDialog.Builder(context);
builder.setIcon(R.drawable.icon)
        .setTitle("title")
        .setMessage("message")
        .setPositiveButton("Button1", 
            new DialogInterface.OnclickListener(){
                public void onClick(DialogInterface dialog,int whichButton){
                    setTitle("click");
                }   
            })
        .create()
        .show();

熟悉吧!看着这一串的链式调用,是不是很舒服呢~~

工厂方法模式

定义:定义一个用于创建对象的接口,让子类决定实例化哪个类。

//抽象产品
public abstract class Product{
    public abstract void method();
} 

//具体产品A
public class ConcreteProductA extends Prodect{
    public void method(){
        System.out.println("我是产品A!");
    }
}
//具体产品B
public class ConcreteProductB extends Prodect{
    public void method(){
        System.out.println("我是产品B!");
    }
}
//抽象工厂
public  abstract class Factory{
    public abstract Product createProduct();
}

//具体工厂
public class MyFactory extends Factory{
    //这里可以设置一个参数,让参数决定实例化哪个类。
    public Product createProduct(){
        return new ConcreteProductA();
    }
}

这里主要分为四大模块:抽象工厂、具体工厂、抽象产品与具体产品。

在客户端中,我们需要哪个产品,就在工厂中生产哪个产品。

在Android中,我们经常会通过Context.getSystemService(String name)方法获取系统级的服务,在这个方法里,通过我们传入的服务名称字符参数来决定返回哪一个对象,各种系统级的服务都会注册在ContextImpl的一个map容器中,这些服务都是单例。所以在这里,用到了单例和工厂方法模式。

public Object getSystemService(String name) {
    if (getBaseContext() == null) {
        throw new IllegalStateException("System services not available to Activities before onCreate()");
    }
    //........
    if (WINDOW_SERVICE.equals(name)) {
         return mWindowManager;
    } else if (SEARCH_SERVICE.equals(name)) {
        ensureSearchManager();
        return mSearchManager;
    }
    //.......
    return super.getSystemService(name);
}

抽象工厂模式

定义:为创建一组相关或者是相互依赖的对象提供一个接口,而不需要制定他们的具体类 。

放个简单栗子:

public abstract class AbstractProductA{
    public abstract void method();
}
public abstract class AbstractProdectB{
    public abstract void method();
}

public class ConcreteProductA1 extends AbstractProductA{
    public void method(){
        System.out.println("具体产品A1的方法!");
    }
}
public class ConcreteProductA2 extends AbstractProductA{
    public void method(){
        System.out.println("具体产品A2的方法!");
    }
}
public class ConcreteProductB1 extends AbstractProductB{
    public void method(){
        System.out.println("具体产品B1的方法!");
    }
}
public class ConcreteProductB2 extends AbstractProductB{
    public void method(){
        System.out.println("具体产品B2的方法!");
    }
}

public abstract class AbstractFactory{
    public abstract AbstractProductA createProductA();

    public abstract AbstractProductB createProductB();
}

public  class ConcreteFactory1 extends AbstractFactory{
    public  AbstractProductA createProductA(){
        return new ConcreteProductA1();
    }

    public  AbstractProductB createProductB(){
        return new ConcreteProductB1();
    }
}

public  class ConcreteFactory2 extends AbstractFactory{
    public  AbstractProductA createProductA(){
        return new ConcreteProductA2();
    }

    public  AbstractProductB createProductB(){
        return new ConcreteProductB2();
    }
}

抽象工厂模式比工厂模式更加抽象。说实话,在实际开发当中,工厂模式已经可以解决大部分情况。

策略模式

定义:策略模式定义了一系列的算法,并将每一个算法封装起来,而且使他们可以相互替换。策略模式让算法独立于使用它的客户而独立变化。

举个例子:比如你现在又很多排序算法:冒泡、希尔、归并、选择等等。我们要根据实际情况来选择使用哪种算法,有一种常见的方法是,通过if…else或者case…等条件判断语句来选择。但是这个类的维护成本会变高,维护时也容易发生错误。这个时候就可以使用策略模式:我们可以定义一个算法抽象类AbstractAlgorithm,这个类定义一个抽象方法sort()。每个具体的排序算法去继承AbstractAlgorithm类并重写sort()实现排序。在需要使用排序的类Client类中,添加一个setAlgorithm(AbstractAlgorithm al);方法将算法注入Client,每次Client需要排序而是就调用al.sort()。

在Android中,我们平时在属性动画中使用的时间插值器,插值器有着不同的策略:线性插值其、加速减速插值器、减速插值器、自定义插值器等。我们在客户端中可以根据不同的需求注入不同的实现策略。

状态模式

定义:当一个对象的内在状态改变时允许改变其行为,这个对象看起来像是改变了其类。状态模式把对象的行为包装在不同的状态对象里,每一个状态对象都有一个共同的抽象状态基类。状态模式的一图是让一个对象在其内部状态改变的时候,其行为也随之改变。
看例子:

public interface TvState{
    public void nextChannerl();
    public void prevChannerl();
    public void turnUp();
    public void turnDown();
}

//具体的状态:关机时,对于操作不做具体响应
public class PowerOffState implements TvState{
    public void nextChannel(){}
    public void prevChannel(){}
    public void turnUp(){}
    public void turnDown(){}

}

//开机时,响应具体的操作。
public class PowerOnState implements TvState{
    public void nextChannel(){
        System.out.println("下一频道");
    }
    public void prevChannel(){
        System.out.println("上一频道");
    }
    public void turnUp(){
        System.out.println("调高音量");
    }
    public void turnDown(){
        System.out.println("调低音量"); 
    }

}

public interface PowerController{
    public void powerOn();
    public void powerOff();
}

//相当于一个电视遥控器。
public class TvController implements PowerController{
    TvState mTvState;
    public void setTvState(TvStete tvState){
        mTvState=tvState;
    }
    public void powerOn(){
        setTvState(new PowerOnState());
        System.out.println("开机啦");
    }
    public void powerOff(){
        setTvState(new PowerOffState());
        System.out.println("关机啦");
    }
    public void nextChannel(){
        mTvState.nextChannel();
    }
    public void prevChannel(){
        mTvState.prevChannel();
    }
    public void turnUp(){
        mTvState.turnUp();
    }
    public void turnDown(){
        mTvState.turnDown();
    }

}

//使用时
public class Client{
    public static void main(String[] args){
        TvController tvController=new TvController();
        tvController.powerOn();
        tvController.nextChannel();
        tvController.turnUp();

        tvController.powerOff();
        //调高音量,此时不会生效
        tvController.turnUp();
    }


}

可以想像到,如果不使用状态模式,直接在客户端使用if--else判断当前状态的话,代码会多么难以维护和混乱。我们把状态封装成了对象,在不同的具体状态有着不同的实现。整个结构就变得很清晰了。

在Android源码中,WIFI管理模块用到了状态模式。当WIFI开启时,自动扫描周围的接入点,然后以列表的形式展示;当wifi关闭时则清空。这里wifi管理模块就是根据不同的状态执行不同的行为。

责任链模式

定义:使多个对象都有机会处理请求,从而避免请求的发送者和接受者直接的耦合关系,将这些对象连成一条链,并沿这条链传递该请求,直到有对象处理它为止。

Android源码中的责任链模式:在Android处理点击事件时,父View先接收到点击事件,如果父View不处理则交给子View,依次往下传递,直到有View 处理它便会停止传递。

解释器模式

定义:给定一个语言,定义它的语法,并定义一个解释器,这个解释器用于解析语言。
这个实际开发中用得比较少。在Android中,我们经常使用的AndroidManifest.xml文件里,<Activity>,<Service>等标签语句,就是一种语法,PackageManagerService就是解释器,通过PackageManagerService解析这些标签,然后保存解析出来的信息。

命令模式

定义:将一个请求封装成一个对象,从而让用户使用不同的请求把客户端参数化,对请求排队或者记录请求日志,以及支持可撤销的操作。

比如,当我们点击“关机”命令,系统会执行一系列操作,比如暂停事件处理、保存系统配置、结束程序进程、调用内核命令关闭计算机等等,这些命令封装从不同的对象,然后放入到队列中一个个去执行,还可以提供撤销操作。

Android中的命令模式:在Android事件机制中,底层逻辑对事件的转发处理。每次的按键事件会被封装成NotifyKeyArgs对象。通过InputDispatcher封装具体的事件操作。

观察者模式

定义:定义对象间一种一对多的依赖关系,使得每当一个对象改变状态,则所有依赖于它的对象都会得到通知并被更新。

观察者模式中主要有以下角色:

比如我们很熟悉的“订阅--发布”系统,就是观察者模式的一个经典应用。有新消息发布时,就会将消息发送给每个订阅者。

Android中,ListView的Adapter中的notifyDataSetChanged(),这个函数通知ListView的每个Item,数据源发生了变化,请重绘。还有BroadcastReceiver广播接收器,也是一种订阅-发布的情况,也属于观察者模式。

备忘录模式

定义:在不破坏封闭的前提下,捕获一个对象的内部状态,并在对象之外保存这个状态,这样,以后就可将对象恢复到原先保存的状态中。

在Android开发中,Activity里的onSaveInstanceState和onRestoreInstanceState我们都很熟悉,用于在异常情况中保存和恢复数据。这就是备忘录模式啦。

迭代器模式

迭代器模式,又称为(Cursor)模式。

定义:提供一种方法顺序访问一个容器对象中的各个元素,而不需要暴露该对象的内部表示。

Java中的Iterator类就是迭代器模式。

在Android开发中,我们使用SQLiteDatabase或者ContentProvider的时候,使用query方法时,通过返回的Cursor对象对数据进行顺序遍历,这就是迭代器模式。

模板方法模式

定义:定义一个操作中的算法框架,而将一些步骤延迟到子类中,使得子类可以不改变一个算法的结构即可重定义该算法的某些特定的步骤。

模板方法实际上是封装了一个固定流程,就像是一套执行模板一样,这些都在父类中定义好,而子类可以有不同的具体实现。

在Android开发中,我们在使用Activity时,用的就是系统给我们提供的模板,onCreate、onStart、onResume......我们只需要在这些方法里去实现我们的逻辑,就可以很轻松的完成一个activity了。

访问者模式

定义:封装一些作用于某种数据结构中各元素的操作,它可以在不改变这个数据结构的前提下定义作用于这些元素的新的操作。

Android中运用访问者模式,其实主要是在编译期注解中,编译期注解核心原理依赖APT(Annotation Processing Tools),著名的开源库比如ButterKnife、Dagger、Retrofit都是基于APT。

中介者模式

定义:中介者模式包装了一系列对象相互作用的方式,使得这些对象不必相互明显调用,从而使他们可以轻松耦合。当某些对象之间的作用发生改变时,不会立即影响其他的一些对象之间的作用保证这些作用可以彼此独立的变化,中介者模式将多对多的相互作用转为一对多的相互作用。

Android中的Binder机制就是一种中介者模式。我们在开发多进程应用的时候,通过Binder这个媒介,实现IPC通信。在Android Framework层中也是如此,系统启动时,各种系统服务会向ServiceManager提交注册,即ServiceManager持有各种系统服务的引用 ,当我们需要获取系统的Service时,比如ActivityManager、WindowManager等(它们都是Binder),首先是向ServiceManager查询指定标示符对应的Binder,再由ServiceManager返回Binder的引用。并且客户端和服务端之间的通信是通过Binder驱动来实现,这里的ServiceManager和Binder驱动就是中介者。

代理模式

定义:为其他类提供一种代理以控制这个对象的访问。

使用场景:当无法或者不想直接访问某个对象或访问某个对象存在困难时可以通过一个代理对象来间接访问,为了保证客户端使用的透明性,委托对象与代理对象需要实现相同的接口。

代理模式在Android中,我们在使用AIDL进行跨进称通信时,操作的对象其实是远程对象的代理,AIDL生成一个代理类,帮我们完成把参数写入到Parcelable对象等操作。

组合模式

定义:将对象组成成树形结构,以表示“部分-整体”的层次结构,使得用户对单个对象和组合对象的使用具有一致性。

在Android中View的结构是树形结构,每个ViewGroup包含一系列的View,而ViewGroup本身又是View。这是Android中非常典型的组合模式。

适配器模式

定义:把一个类的接口变换成客户端所期待的另一个接口,从而使原本因接口不匹配而无法在一起工作的两个类能够在一起工作。

在Android开发当中,我们在使用ListView或者RecyclerView的时候,我们知道数据源和ListView是没有关系的,我们通过给ListView设置适配器,适配器中提供了getView方法把数据源转化为ListView需要的对象,View。然后完成工作。这就是适配器模式。

装饰模式

定义:动态的给一个对象添加额外的智者,就增加功能来说,装饰模式比子类继承的方式更灵活。

装饰模式是以对客户端透明的方式拓展对象的功能,是继承关系的一个替代方案,而代理模式则是给一个对象提供一个代理对象,并使用代理对象来控制对原有对象的引用。装饰模式为所装饰的对象增强功能,代理模式对代理的对象施加控制,不进行增强。

Android中,ContextWrapper是Context的装饰类。

享元模式

定义:使用享元对象有效地支持大量的细粒度对象。

享元模式主要是为了重用对象,在系统中存在大量相似对象时,可以使用享元模式。比如Java中的常量池,线程池等。

在Android中,每次我们获取Message时调用Message.obtain()其实就是从消息池中取出可重复使用的消息,避免产生大量的Message对象。

外观模式

定义:要求一个子系统的外部与其内部的通信必须通过一个统一的对象进行。

Android内部有很多复杂的功能比如startActivty、sendBroadcast、bindService等等,这些功能内部的实现非常复杂,如果你看了源码你就能感受得到,但是使用者无需关心它内部实现了什么,只需要使用这些统一的高层接口就可以了。

桥接模式

定义:将抽象部分与实现部分分离,使他们独立地进行变化。

在Android中,View的视图层级与执行真正的硬件绘制相关类之间的关系可以看作是一种桥接模式。对于一个View来说,它有两个维度的变化,一个是它的描述比如Button、TextView等等他们是View的描述维度上的变化,另一个维度就是将View真正绘制到屏幕上,这跟Display、HardwareLayer和Canvas有关。这两个维度可以看成是桥接模式的应用。

总结

讲道理,看到那么多的设计模式我懵比了很久。在开发过程中,我们要注意运用设计模式,写出更加好的软件。当然,绝对要记住,拒绝过度设计,不要为了设计而设计。

上一篇下一篇

猜你喜欢

热点阅读