【转】Android系统设计中的设计模式分析(汇总)

转自:http://blog.csdn.net/a345017062/article/details/7904649

1、 开闭(OCP)

简介:要扩展,不要修改。比如我对外提供了一个接口。现在想更新的话,不要直接修改这个接口,而是提供另外一个接口,然后通知大家在什么时间之前切换到这个新接口。

举例:这个设计模式无处不在,Android每次升级都会提供一些新的API,有一些较老的API就会置为deprecated。如从level  1就支持的Service.onStart,在level 5中,已经被Service.Service.onStartCommand替换,但Service.onStart依然保留没有去掉,以便继续提供过渡期的支持。

2、 合成复用

简介:少用继承(耦合性比较强),多用合成关系(灵活):接口、工具类等。

举例:进行任何开发,都会从一个主程序类,如Android中的Activity。我们需要在开发中把Activity中可以调用到的所有功能能分开的尽量分开,避免Activity太过臃肿。如Activity中需要用到读取资源的方法:getLayout、getDrawable等,因为这些功能属于和资源相关的,与Activity提供的生命周期控制功能相对独立,所以完全可以抽出来放到Resource里面。而在Activity中只提供一个getResource来获取使用就可以了。这样,任何模块都可以通过Context来获取并使用Resource。Resource所代表的这个资源管理模块的

用性更强。

3、 依赖倒转(DIP)

简介:分清细节和抽象的使用场景。传递参数、组合关系中,尽量使用抽象层的

举例:拿ImageView.setImageDrawable方法来举例。ImageView可以显示Bitmap,Xml,ninepatch等各种资源,根据依赖倒转原则的指导,我们完全不用根据每种类型都在ImageView类中开放一个方法,而是把它们都抽象成Drawable,而ImageView只接收Drawable就OK了。

4、 接口隔离

简介:每个接口只干一件事,不要把多个功能揉到一个接口中去。

举例:使用依赖倒转原则,可以把N个方法合成为一个方法,但这N个方法一定是同一个功能,只是不同的参数类型。如果功能不同,就不要生硬地拼在一起了,保持每个方法小巧而灵活。如果真的有一个需求需要连续调用N个小功能了,就那再上面再套一层壳吧,参见:调解者模式。

5、 适配器模式

简介:不同的数据提供者使用一个适配器来向一个相同的客户提供服务。

举例:这个最常见了,ListView、GridView都是经典例子,利用ListAdapter等把各种各样的数据和View连接在一起。

6、 里氏代换(LSP)

简介:一个继承树中,所有树节点都是抽象类,所有的叶子节点都是具体实现类。使用父类的地方可以传入任何一个子类。

举例:这个最经典的就是Android中的View继承树了,所有传入ViewGroup的方法可以传入任何一个继承自ViewGroup的容器;可以传入View的方法可以传入任何一个ViewGroup或者继承自View的控件。如setContentView(Viewv),既然参数是View,那么传入任何一个继承自View的控件都可以,如TextView,LinearLayout等。

7、 建造者模式

简介:可以分步地构造每一部分。

举例:这个模式的核心在于分步构造一个对象,Android中的经典就是AlertDialog.Builder的使用。

8、命令模式(Command)

简介:把请求封装成一个对象发送出去,方便定制、排队、取消。

举例:如通过Handler.post向MessageQueue发送一个Message命令,命令中包含参数arg1、arg2、what等参数,Handler内部会调用handleMessage来执行这个Message命令。

9、享元模式

简介:运用共享技术有效地支持大量细粒度的对象。

举例:Message.obtain通过重用Message对象来避免大量的Message对象被频繁的创建和销毁。

10、迭代器(Iterator)模式

简介:提供一个方法顺序访问数据集合中的所有数据而又不暴露对象的内部表示。

举例:如通过Hashtable.elements方法可以得到一个Enumeration,然后通过这个Enumeration访问Hashtable中的数据,而不用关心Hashtable中的数据存放方式。

11、调解者模式(Mediator)

简介:一个对象的某个操作需要调用N个对象的M个方法来完成时,把这些调用过程封装起来,就成了一个调解者

举例:如Resource.getDrawable方法的实现逻辑是这样的:创建一个缓存来存放所有已经加载过的,如果getDrawable中传入的id所对应的Drawable以前没有被加载过,那么它就会根据id所对应的资源类型,分别调用XML解析器生成,或者通过读取包中的图片资源文件来创建Drawable。

而Resource.getDrawable把涉及到多个对象、多个逻辑的操作封装成一个方法,就实现了一个调解者的角色。

12、备忘录模式(Memento)

简介:不需要了解对象的内部结构的情况下备份对象的状态,方便以后恢复。

举例:如Activity的onSaveInstanceState和onRestoreInstanceState就是通过Bundle这种序列化的数据结构来存储Activity的状态,至于其中存储的数据结构,这两个方法不用关心。这算是备忘录模式的一个经典例子。

13、观察者模式(Observer)

简介:一个对象发生改变时,所有信赖于它的对象自动做相应改变。

举例:我们可以通过BaseAdapter.registerDataSetObserver和BaseAdapter.unregisterDataSetObserver两方法来向BaseAdater注册、注销一个DataSetObserver。这个过程中,DataSetObserver就是一个观察者,它一旦发现BaseAdapter内部数据有变量,就会通过回调方法DataSetObserver.onChanged和DataSetObserver.onInvalidated来通知DataSetObserver的实现类。

14、原型模式(Prototype Pattern)

简介:在系统中要创建大量的对象,这些对象之间具有几乎完全相同的功能,只是在细节上有一点儿差别。

举例:比如我们需要一张Bitmap的几种不同格式:ARGB_8888、RGB_565、ARGB_4444、ALAPHA_8等。那我们就可以先创建一个ARGB_8888的Bitmap作为原型,在它的基础上,通过调用Bitmap.copy(Config)来创建出其它几种格式的Bitmap。

另外一个例子就是Java中所有对象都有的一个名字叫clone的方法,已经原型模式的代名词了。

15、代理模式(Proxy)

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

举例:翻呀翻,终于找到现成的例子了,这就是AIDL。所有的AIDL都一个代理模式的例子。假设一个Activity A去绑定一个Service S,那么A调用S中的每一个方法其实都是通过系统的Binder机制的中转,然后调用S中的对应方法来做到的。Binder机制就起到了代理的作用。

16、状态模式(State)

简介:状态发生改变时,行为改变。

举例:View.onVisibilityChanged方法,就是提供了一个状态模式的实现,允许在View的visibility发生改变时,引发执行onVisibilityChanged方法中的动作。

17、策略模式(Strategy)

简介:定义了一系列封装了算法、行为的对象,他们可以相互替换。

举例:Java.util.List就是定义了一个增(add)、删(remove)、改(set)、查(indexOf)策略,至于实现这个策略的ArrayList、LinkedList等类,只是在具体实现时采用了不同的算法。但因为它们策略一样,不考虑速度的情况下,使用时完全可以互相替换使用。


Factory:
标准设计模式中存在两种工厂模式,可以参见下面这两个地址,里面有详细的介绍。
Factory
http://blog.csdn.net/cjjky/article/details/7314118
Abstract Factory
http://blog.csdn.net/cjjky/article/details/7346893
其要点都在于Client只关心抽象工厂和抽象产品,而不关心具体的工厂和工厂创建出来的具体的产品是什么。
另外,对Android中存在的Factory进行了整理,大概分了两类:
一类是产品唯一且固定的,与标准的工厂模式定义不一样,但也算是对工厂模式的活学活用。
SSLCertificateSocketFactory
SocketcreateSocket(String host, int port, InetAddress localAddr, int localPort)
SocketcreateSocket(InetAddress addr, int port)
BitmapFactory
BitmapdecodeByteArray(byte[] data, int offset, int length, BitmapFactory.Options opts)
BitmapdecodeByteArray(byte[] data, int offset, int length)
BitmapdecodeFile(String pathName)
另一类是算是标准的工厂模式。Android定义了抽象工厂ViewSwitcher.ViewFactory和ViewSwitcher.ViewFactory,还定义了抽象产品View
ViewSwitcher.ViewFactory
ViewmakeView()
LayoutInflater.Factory
ViewonCreateView(String name, Context context, AttributeSet attrs)


Builder:
参见:http://blog.csdn.net/cjjky/article/details/7327200
标准设计模式中的Builder规定由抽象Builder把构建对象的各个步骤定义好抽象方法,具体实现类Builder去实现这些抽象方法,从而构造出不同的对象。
而Android中的Builder模式稍稍变通了一下,没有抽象Builder角色,直接为一个对象配备了固定的Builder,然后在Builder中把构造对象的步骤开放出来,由使用者分步调用。如:
AlertDialog.Builder
Notification.Builder
Uri.Builder


Stategy:
参见:http://blog.csdn.net/cjjky/article/details/7322688
每一个具体的Interpolator都代表一个具体的算法。Interpolator类对它们进行了抽象,扮演了一个Strategy角色。而Animator算是使用Strategy的Context。


Proxy:
参见:http://blog.csdn.net/cjjky/article/details/7330657
代理模式的四种应用场合:
第一:远程代理,也就是为一个对象在不同的地址空间提供局部代表,这样可以隐藏一个对象存在于不同地址空间的事实。
第二:虚拟代理,是根据需要创建开销很大的对象,通过它来存放实例化需要很长时间的真实对象。
第三:安全代理,用来控制真实对象访问时的权限。
第四:智能引用,是指当调用真实对象时,代理处理另外一些事。
Android中的AIDL属于第一种应用。


Observer:
参见:http://blog.csdn.net/cjjky/article/details/7384951
模式的应用场景及特点
1、多个不同的对象都对同一个对象的状态改变感兴趣。
2、对象之间要求很松散的耦合时使用。
3、可以向Observerable中添加/删除Observer
4、Observerable对Observer的数量不做限制,有状态改变时通知所有的Observer。


Decorator:
参见:http://blog.csdn.net/cjjky/article/details/7478788
个人见解:
除模式本身定义的场景外,还比较适用于被包装的类不能继承、不了解细节的情况。比如从Resolver中获取到系统的Cursor时,实际只取到了Cursor这个接口,如果想扩展Cursor的功能而又不改变接口,只有Decorator最合适。这种情况下是无法继承的。


Facade:
参见:http://blog.csdn.net/cjjky/article/details/7570632
实现一个功能需要先调用A的a方法,再调用B的b方法,再调用C的c方法时,可以定义一个Facade类,在里面包含了对a,b,c的调用集合。这样外部使用一个Facade就可以了。


State:
参见:http://blog.csdn.net/cjjky/article/details/7585207
当控制一个对象状态转换的条件表达式过于复杂时的情况。把状态的判断逻辑转移到表示不同状态的一系列类当中,可以把复杂的判断逻辑简化。当一个对象的行为取决于它的状态,并且它必须在运行时刻根据状态改变它的行为时,就可以考虑使用状态模式了。


Visitor
先贴一个有代码例子,且好理解的文章:
http://www.cnblogs.com/shanghaif/archive/2008/12/08/1350417.html
再转发一个我认为最形象的解释。
如果有一棵继承树,你要使用某个独立的对象遍历这棵树,并且呼叫树上某一个共同的方法,那么你使用iterator。比如这是一棵苹果树,你使用一个摘苹果的杆子把苹果一个一个摘下来,这就是iterator。 
现在你有好几棵树,苹果树、葡萄树、酸枣树等,对每一种果实,你都有不同的杆子,摘取果实。这个时候就可以使用visitor模式。
当然,Java对象都源自Ojbect类,所以原则上所有的对象都来自同一棵树,以Object为根。这时候不妨假设一棵树有不同的子树,或者同一棵树上有不同的果实。 
不使用visitor模式行不行,行。那你就使用Iterator模式,像这样: 
while(it.hasNext()){ 
    Object   o   =   it.next(); 
    if   (苹果   instanceof   o){...} 
    else   if(葡萄   instanceof   o){...} 
    。。。 

这样好像也没什么问题,只是一旦有操作进来,比如要给不同的树打不同的农药,就要改写这个条件转移。 
用了Visitor模式之后呢,奇迹发生了,你拿出所有的杆子举到每一个果实那里,苹果会自己找到摘苹果的杆子,让杆子把自己摘下来,葡萄会找到摘葡萄的杆子,把自己摘下来。 
如果有打农药、授粉等等任务进来,Visitor模式可以允许动态加入一个新的visitor类代表打农药、授粉等,做到这一点不需要修改代码。这就是OCP。你把所有的农药都放到每一个果实跟前,果实就自行找到正确的农药自己打上。把所有的花粉放到果实跟前,果实就自己找到正确的花粉授粉。 
你只有这些种水果杆子/农药/花粉,如果你有新的水果种类,对不起,只好改写代码。Visitor模式不支持这种情况下的OCP。


Template Method
参见:http://blog.csdn.net/hguisu/article/details/7564039
大意是父类负责逻辑组合部分,实现共同的逻辑部分,并把不同子类具有的不同逻辑部分通过protected abstract方法开放出去,由子类负责具体的实现。
在Android中,View的源码中,draw()方法承担了逻辑组合的功能,负责所有绘制逻辑的实现。同时View也实现了共同的逻辑部分,如绘制padding,操作matrix等。而不同的子类的不同具体绘制形为是通过实现抽象方法onDraw实现的。


UML中,不同的对象之间的关系有Generation,Implementation,Dependence,Association,Aggregation,Composition这六种关系。其中,Generation,Implementation,Dependence这个比较容易


理解,代表了程序中的类继承、接口实现、参数传递。但其它几个就比较不好理解了。下面是找到的两篇说得比较清楚明白的文章:
UML图中类之间的关系:依赖,泛化,关联,聚合,组合,实现
http://blog.csdn.net/hguisu/article/details/7609483
组合,关联,聚合的区别
http://blog.csdn.net/baobeiSimple/article/details/1648617

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值