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

来源:互联网 发布:剑三琴萝捏脸数据 编辑:程序博客网 时间:2024/05/21 19:24

转自: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 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 英雄联盟活动送皮肤没送怎么办 电脑换完系统有些页面打不开怎么办 王卡助手交手机费页面打不开怎么办 在浏览器上打不开路由器页面怎么办 英雄联盟读条的时候自动关机怎么办 手机的位置信息开不了怎么办呢 滴滴车主接到乘客返回路程要怎么办 移动换话费积分是发什么短信怎么办 手机店积分换手机被贷款怎么办 心悦俱乐部礼包已过期是怎么办 心悦兑换的东西不是账号绑定怎么办 心悦会员绑定的手机号不用了怎么办 想在京东商城开个网店怎么办呢 京东买了东西收货了不想要了怎么办 京东转卖的商品有问题怎么办 如果衣服下架了然后有退货怎么办 想买二手车可没有懂车的人怎么办 买车的时候异地车牌回家怎么办 天猫下单显示下单人数太多券怎么办 英雄联盟进入游戏后无限崩溃怎么办 打开电视显示百度影棒打不开怎么办 家里路由器网速一会快一会慢怎么办 用快看影视下载电影网速太慢怎么办 苹果手机下载东西网速特别慢怎么办 网上买重庆时时彩输了很多钱怎么办 找不到自己在哪个平台借过钱怎么办 九游账号绑定手机之前绑定的怎么办 九游充过钱的游戏忘了游戏名怎么办 百度网盘密码忘了申诉不了怎么办 手机号被别人注册了百度账号怎么办 快手被盗找回时出来重置密码怎么办 魅族账号密码和密保都忘记了怎么办 vivo账号的密保问题忘了怎么办 oppo账号密保问题忘了怎么办 小米手机刷了机忘了账号密码怎么办 忘了小米账号的密码是多少怎么办 千牛账号在手机上被限制登录怎么办 违规的千牛账号被限制登录了怎么办 苹果id和锁屏密码忘记了怎么办 感应门的编程密码忘记了怎么办 交易猫买的号被找回了怎么办