android 源码设计模式(总结)

1.面向对象6大原则

solidd(single, open, lishi, interface,

1 单一职责原则(优化第一步)

一个类应该负责单一的功能,应该是一组相关性很高的函数,数据的封装,两个完全不一样的功能不应该放在一个类中。

2 开闭原则(程序更稳定)

类,模块,函数等对于拓展是开放,对于修改是关闭的,也就说重要的逻辑都是无法修改的,如果需要修改功能可以通过继承拓展的方式来实现。

3 里氏替换原则(扩展性更强)

所有引用基类的地方,必须能透明的使用其子类的对象。实际上就是抽象继承,在需要调用子类继承方法的时候,直接用父类去调,很明显的就是android中所有的IxxxxManager,实际上拿的都是子类xxxxManagerService具体实现的方法

4 依赖倒置原则(项目变化能力增强)

高层不应该依赖于低层,而应该依赖低层的抽象,抽象类中不应该出现实现类。比如在工具类(高层类,相当于管理者)中,尽量不要出现实现类(低层类,最底层的class),因为这样可能会导致,以后这个实现类满足不了需求的时候需要去修改这个工具类才能达到拓展的目的。

5 接口隔离原则(更灵活)

尽量做到接口的拆分,将庞大臃肿的接口拆分成具体的接口,用户不用每一次都去实现接口中它不需要的方法。

6 迪米特原则(更好的扩展性)

一个类中对其他对象了解的越少越好,全力解耦,自己做好自己的事情,其他人的事情让他们自己去做,也不要去帮着做。


2. 单例模式

(1)饿汉模式:

public class SingleTon {
    private SingleTon mInstance = new SingleTon();
    public static SingleTon getInstance(){
        return mInstance;
    }
}

内部持有指向自己的静态变量

(2)懒汉模式:

public class SingleTon {
    private static SingleTon mInstance;

    SingleTon(){
    }

    public static synchronized SingleTon getInstance(){
        if(mInstance == null){
            mInstance = new SingleTon();
        }
        return mInstance;
    }
}

宗旨就是持有自己的静态私有变量,首次初始化一下,之后就一直有了。节省开销,但是首次加载会比较慢,并且每次都需要同步,开销略大,不建议使用。

(3)Double check lock模式

public class SingleTon {
    private SingleTon mInstance;

    SingleTon(){
    }

    public static SingleTon getInstance(){
        if(mInstance == null){
            sychronized(SingleTon.class){

               if(mInstance == null){
                mInstance = new SingleTon();
               }
            }
        }
        return mInstance;
    }
}

为什么要叫double check是因为它检查了两次,第一次检查完为空了之后,需要考虑到线程安全问题,上锁再进行new,这样就保证了只创建了一个SingleTon,且不用每一次调用这个方法都要进行同步。缺点也是第一次调用的时候反应比较慢,且有极小的可能会失效,但是效率较高,资源利用率也高

(4)静态内部类单例模式

public class SingleTon {
    public static SingleTon getInstance(){
       return InstanceHandler.mInstance;
    }
    private static class InstanceHandler{
        private static final SingleTon mInstance = new SingleTon();
    }
}

这种方法解决了DCL的失效问题,这是推荐使用的最好的单例模式

(5)容器实现单例

举个例子,就是安卓源码中的service注册管理以及serviceManager注册管理都是用的map保存。

源码中的使用:

(1)就是上面所说的service管理
(2)ActivityMangerNative.getDefault()方法

优缺点:

优点:节省资源,优化和共享资源访问
缺点:Context内存泄露


3. 构造者模式

创建一个builder类,然后只把你用的到的参数传进去。

源码中的使用:

(1)AlertDialog.Builder

优缺点:

优点:良好的封装性和可扩展性
缺点:产生了多余的Builder对象,浪费了内存


4. 原型模式(本质就是对象拷贝)

不通过new去生成一个对象,而直接通过clone一个已经存在的对象来生成一个新的对象。我们只要去implements Cloneable接口,然后复写它的clone方法即可。

(1)浅拷贝

将原始对象的所有字段统统拷贝过去,且仅仅是单纯的拷贝

(2)深拷贝

对于除了基本类型的字段,采用相应数据类型的clone方法,如:

doc.mImages = (ArrayList) this.mImages.clone();

源码中的使用

(1)ArrayList的clone方法
(2)Intent的clone方法

优缺点

优点:直接clone,可以免去再次调用构造函数,节省资源
缺点:不会再次调用构造函数,需要注意这个潜在的问题


5. 工厂模式

一个抽象的工厂类,有一个抽象的生产方法。一个具体的工厂类继承这个抽象的工厂,然后想生产什么就生产什么,只要是抽象生产方法返回的基类的任意子类都行。

源码中的使用

(1)AbstractList和AbstractSet就是那个抽象工厂,这两个抽象的工厂类里面都一个iterator的迭代器方法用来遍历的,arrayList继承了AbstractList有它的iterator方法实现,HashSet和MapSet则分别是AbstractSet的具体工厂实现。

优缺点

优点:降低了对象间的耦合,将具体的实现交给子类去完成,增强了拓展性
缺点:如果要添加新的产品,就需要写一个新的产品类,而且是抽象类放到工厂才行,类结构就会变得复杂化了。


6. 抽象工厂模式

跟工厂模式不同的是,一个抽象工厂中可以有多个抽象的方法,那么具体工厂可以有多种不同的实现方式

源码中的使用

(1)比如继承了Activity的onCreate()方法,onResume()等各种生命周期的方法
(2)继承了service,里面的onBind等方法。

优缺点

优点:降低了对象间的耦合,很灵活
缺点:类会变得很多,如果要添加新的产品,就需要写一个新的产品类,而且是抽象类放到工厂才行,类结构就会变得复杂化了。


7. 策略模式

将不同的算法都封装起来,选择你所需要的算法,比如我们类中常用到的需要将时间戳转换成不同的格式,然后我们就会在一个Util类里面去定义不同的format方法。

源码中的使用

(1)时间插值器,我们在制作动画的时候使用到的不同的时间插值器就是不同的算法封装

优缺点

优点:结构清晰,简单直观;耦合较低,扩展方便;封装彻底,数据安全。
缺点:随着策略的越来越多,子类也会变得越来越多。


8.状态模式

说白了就是在一个类的内部定义一个变量,这个变量可以去控制某些方法是否可行。比如说我们在adapter中经常使用的是否被选中啊,选中的position啊等状态会在某些方法中需要对这些状态进行判断。

源码中的使用

(1)wifi控制器,在源码的WifiSetting中,我们就能看到我们需要去把wifi按钮打开,才能够继续做wifi的连接操作,那么wifi的连接操作的方法里面就会去判断是否已经wifiEnable了
(2)handler的handleMessage根据which判断也是这个道理

优缺点

优点:将繁琐的状态判断都放在一个结构清晰的状态类中进行管理,增加了可扩展性和可维护性
缺点:类和对象的个数变多


9. 责任连模式

将类一环扣一环,组成一个链,基类中定义一个next对象,并且有一个抽象method,子类实现的时候可以指定下一个类,并在实现method的时候指定如果自己没有解决这个method可以交给下一个类来处理,这样就是一个责任链模式

源码中的使用

(1)View中的dispatchTouchEvent,如果没有拦截就不断的从外往里分发,如果没有消费掉触摸事件,会不断的从里向外专递。
(2)handler的handleMessage根据which判断也是这个道理

优缺点

优点:请求者和处理者之间的关系解耦
缺点:遍历太多影响性能


10.解释器模式

将特定的符号解释其意义就是解释器模式,比如解释一段算数运算符,解释一个xml文件等

源码中的使用

(1)PackageParser解释AndroidManifest.xml文件就是将文件中的东西都解释出来放到自己的属性中保存起来
(2)lambda风格底层实现应该也是解释器

优缺点

优点:灵活的扩展性,只要文法上有所增加,我们只需要去修改相应的解释器就行了
缺点:每条文法都需要一个解释器,会导致类很多,很难维护,如果文法相当复杂,并不推荐使用解释器模式


11. 命令模式

将一系列的方法都封装起来,用户不用去关心这个方法里面执行了多少步骤,只需要去调用一个方法即可,哪怕这个方法中调用了很多其他的一连串的方法,对外都是隐藏的。

源码中的使用

(1)并没有纯粹的命令模式,基本都会夹杂这其他的设计模式,比如我们去finish一个activity,看似只是单单的调用了finish方法,实际上里面有一长串相当复杂的逻辑只是都封装起来了

优缺点

优点:弱耦合,控制灵活,扩展性很强
缺点:类的膨胀,大量的衍生类


12.观察者模式

observable,当一个对象的状态改变的时候,所有观察它的对象都可以第一时间得到通知

源码中的使用

(1)所有的adapter都会去设置Observer,然后当调用NotifyDataSetChanged方法的时候会通知界面更新。
(2)EventBus
(3)广播

优缺点

优点:将观察者和被观察者完全隔离,被观察者自己都不知道被谁观察了,耦合度低,很灵活
缺点:观察者多了之后会造成调试困难,如果是同步执行的话一个观察者卡顿会造成卡顿,这个时候需要异步的方式。


13.备忘录模式

将状态保存,下次再次需要使用的时候再进行恢复

源码中的使用

(1)activity的onSaveInstanceState和onRestoreInstanceState

优缺点

优点:给用户提供了可以恢复的机制,实现了信息封装,用户不用去关心保存恢复的具体细节
缺点:类的成员变多,每一次保存都会消耗掉系统的资源


14.迭代器模式

提供一个顺序访问内部元素的方法,又不会暴露具体的内部情况,使用的很多只要是实现了Iterator的,都是迭代器模式。

源码中的使用

(1)数据库的cursor就是迭代器模式
(2)ArrayList,Set等只要是数组性质的都会有iterator方法

优缺点

优点:弱化了容器类和遍历算法之间的关系,可以通过不同的iterator实现类去进行不同的遍历
缺点:类文件增加


15.模板方法模式(流程封装)

把具体的实现顺序写死,而将每一步具体的方法放出去让子类实现的方式。

源码中的使用

(1)Activity的生命周期
(2)AsyncTask的生命周期

优缺点

优点:封装不变的部分,扩展可变的部分
缺点:可读性降低,难以理解。


16.访问者模式

定义一个接口,创建同名不同传参的接口方法,然后实现这个接口的类去对不同的对象,获取它所需要的不同的字段。这样就达到了可以对不同的对象做不同的操作的目的了

public interface Visitor{
    public void visit(Engineer engineer);

    public void visit(Manager manager);

    public void visit(Ceo ceo);

    public void visit(Cto cto);
}

源码中的使用

(1) 注解中的AbstractProcessor解析时,使用到的ElementVisitor接口类就是使用了访问者模式,可以对多个不同的对象进行访问。

优缺点

优点:数据结构和数据操作可以解耦,操作就做操作的事情,根据不同的传参,来获得不同的数据对象,职责单一。
缺点:在interface依赖了具体类二没有依赖抽象类,违背了依赖倒置原则,在实现访问者接口的子类中会去各种操作其他类的细节,违反了迪米特。

17. 中介者模式mediator

专门设计一个中介者的抽象类,将事件双方都定义在这个中介者类中,通过继承中介者,来操作它的属性对象。

源码中的使用

(1) KeyguardViewMediator这个中介者类中定义了很多manager,然后在它的很多方法中对这些manager做了相应的操作。

优缺点

优点:避免产生过多的依赖,直接在中介者内部解决。
缺点:会使逻辑变得复杂


18.代理模式

为其他对象提供一个代理用来控制对这个对象的访问。一个proxy类对象中持有了访问对象的引用,然后通过这个proxy的操作来达到对访问对象数据的访问。

源码中的使用

(1) 所有的binder相关类中的IxxxxManager类中都会有一个proxy对象,来对远程的binder对象进行代理访问

优缺点

优点:控制对象访问,内部封装,提高访问安全
缺点:基本没有缺点,最多就是类文件增加(设计模式的通病)


19.组合模式

将对象组合成树形结构,比如数和节点的定义,就是组合模式。tree中定义leaf,Object中定义node等等

源码中的使用

(1) View和ViewGroup的嵌套组合

优缺点

优点:适用于分层的复杂对象,让高层的对象可以在内部直接对整个层次结构进行控制
缺点:新增构件的时候会比较复杂。


20.适配器模式adapter

用户只需要使用统一的接口,可以适配所有的实现接口。

源码中的使用

(1) BaseAdapter

优缺点

优点:更好的复用性,更好的扩展性
缺点:过多使用适配会让系统变得零乱复杂


21.装饰模式Decorator

动态的给对象添加额外的职责和功能,具体类继承基类,并在内部持有一个基类对象,然后直接进行代理,并可以在复写基类方法的时候去增加额外的功能。

源码中的使用

(1) ContextWrapper继承了Context,并且内部持有了Context对象,但是基本都是原封不动的调用Context的方法

优缺点

与代理模式一样,装饰模式更注重的是增加功能,在调用访问对象的方法时增加一些其他的功能,而代理模式更注重的是对访问对象本身的访问进行控制。


22.享元模式

对于同样的请求,保存其结果。很好的例子就是map容器,当请求的key存在的时候,就直接get出来用,如果这样就不用反复的每一次都请求。

源码中的使用

(1) 实际上单例我们都可以把他理解位是享元模式,比如我们在ActivityThread中的main方法定义的mLooper是共享的,就让我们在Activity中直接定义new Handler而不需要去为handler设置looper。

优缺点

优点:大大的减少对象的创建,节省了内存
缺点:为了使对象可以共享,需要将享元对象的部分状态外部化,会是系统变得复杂。


23.外观模式,门面模式Facade

基本第三方都是使用的这种模式,最高层接口做统一的接口方法封装,然后子类去实现这个最高层的接口,去分别实现它的方法,而用户只需要去调高层的接口方法就可以达到相应的效果,简单易用,又隐藏了具体的实现。

源码中的使用

(1) Context这个高层抽象类封装的抽象方法,如startActivity,startService等等

优缺点

优点:大大的减少对象的创建,节省了内存
缺点:为了使对象可以共享,需要将享元对象的部分状态外部化,会是系统变得复杂。


24.桥接模式bridge

抽象部分和实现部分分离,抽象类中持有另外一个抽象类,通过调用方法来对另外一个抽象类进行操作,那么去继承这个抽象类的子类,就可以对那个持有的抽象对象进行修改。

源码中的使用

(1) 在一个类中对另外一个抽象类进行操作的都可以认为是桥接模式,比如Canvas对view进行绘制操作
(2) 比如adapter对adapterView进行操作

优缺点

优点:分离抽象与实现,扩展灵活,对用户透明
缺点:理解简单,设计复杂。

你可能感兴趣的:(android 源码设计模式(总结))