读Android之大话设计模式--18种设计模式(四):结构型设计模式
10,适配器模式
http://www.cnblogs.com/guoshiandroid/archive/2011/06/05/2073262.html
适配器模式解释:
适配器模式(Adapter Pattern):将一个类的接口转换成客户希望的另外一个接口。Adapter模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。
适配器分为对象适配器和类适配器。
对象适配器使用组合方式,不仅可以适配某个类,也可以适配该类的任何子类,如果子类中加入新的行为,只需要让组合对象是子类就可以解决灵活性的问题;而类适配器因为采用的是继承的方式,所以只能够采用某个特定的被适配类,这就有一个很大的优点,那就是不需要实现整个被适配类,而且在必要的时候还可以覆盖被适配者的行为。
英文定义为:Convert the interface of a class into another interface clients expect.
对象适配器所涉及的角色如下:
目标(Target)角色:是客户端期待得到的接口。目标角色可以是具体类也可以是抽象类。
源(Adaptee)角色:需要适配的接口,就是被适配的对象。
适配器(Adapter)角色:这是对象适配器模式的核心。适配器把源接口转换成目标接口,很显然,适配器角色不可以是接口,而必须是具体的类。
适配器模式深入分析:
我们经常碰到要将两个没有关系的类组合在一起使用,第一解决方案是:修改各自类的接口,但是如果我们没有源代码,或者,我们不愿意为了一个应用而修改各自的接口。这时候就不能够采用此种方案了,而且修改源码必然的要影响到和这些类相关的类和对象;第二种方式:使用一个适配器,把原来的接口转变为客户所需要的目标接口,在源接口和客户端之间建立一座桥梁,是源接口不用做任何修改就可被目标接口使用。
适配器模式的目的在于:如果客户需要使用某个类的服务,而这项服务是这个类用一个不同的接口提供的,那么,可以使用适配器为客户提供一个期望的接口。
客户端使用适配器的具体过程如下:
第一步:客户端通过目标接口调用适配器的方法对适配器发出请求。
第二步:适配器使用被适配接口把请求转换成被适配器者的一个或者多个调用接口。
第三步:客户端收到调用的结果,但是并未觉察到这一切是适配器在起转换作用。
一般情况下而言,笔者更提倡使用对象适配器,这是因为对象适配器符合良好的面向对象的设计原则,对象适配器使用对象组合,用对客户端适用的接口来包装被适配者,这种做法带来的另外一个优点是使用于被适配这的地方,也适用于被适配者的任何子类;而如果使用类适配器的话,就会丧失这种灵活性,同时类适配是的目标角色不可以是类,因为Java是单继承语言。
适配器模式的优缺点分析:
优点:
使用适配器模式,能够将一个系统的接口和另外一个系统的接口联系起来,从而使得原本不可以在一起工作的类能够在一起工作,适配器模式强调了对接口的转换。
缺点:
对于类适配器而言,不能够适配类的子类;而对于对象适配器而言,重新定义被适配类的行为比较的困难,但是也并非说不可能,这个时候需要使用子类继承的方式来使用修改了被适配类的子类。
适配器模式的实际应用简介:
在大规模的系统开发过程中,我们常常碰到诸如以下这些情况:我们需要实现某些功能,这些功能已有还不太成熟的一个或多个外部组件,如果我们自己重新开发这些功能会花费大量时间;所以很多情况下会选择先暂时使用外部组件,以后再考虑随时替换。但这样一来,会带来一个问题,随着对外部组件库的替换,可能需要对引用该外部组件的源代码进行大面积的修改,因此也极可能引入新的问题等等。如何最大限度的降低修改面呢?Adapter模式就是针对这种类似需求而提出来的。Adapter模式通过定义一个新的接口(对要实现的功能加以抽象),和一个实现该接口的Adapter(适配器)类来透明地调用外部组件。这样替换外部组件时,最多只要修改几个Adapter类就可以了,其他源代码都不会受到影响。
具体来讲,Adapter模式可应用于如下的情况:
1、系统需要使用现有的类,而此类的接口不符合系统的需要。
2、想要建立一个可以重复使用的类,用于与一些彼此之间没有太大关联的一些类,包括一些可能在将来引进的类一起工作,这些源类不一定有与一致的接口。这种情况从不同的角度考虑,可能被划入Facade模式的范畴,但从与现有设计适配的角度考虑该问题,则将其划归Adapter模式也是可以理解的。
3、通过接口转换,将一个类插入另一个类系中。
温馨提示:
一般情况下而言,笔者更提倡使用对象适配器,这是因为对象适配器符合良好的面向对象的设计原则,对象适配器使用对象组合,用对客户端适用的接口来包装被适配者,这种做法带来的另外一个优点是使用于被适配这的地方,也适用于被适配者的任何子类;而如果使用类适配器的话,就会丧失这种灵活性,同时类适配是的目标角色不可以是类,因为Java是单继承语言。
11,代理模式
http://www.cnblogs.com/guoshiandroid/archive/2011/06/07/2074565.html
代理模式解释:
代理模式(Proxy Pattern)是构造型的设计模式之一,代理模式就是给某一个对象提供一个代理对象,并由代理对象控制对源对象的引用。就是一个人或者一个机构代替另一个人或者另一个机构去采取一些行动,以控制对这个对象的访问。
所谓代理,是指具有与代理元(被代理的对象)具有相同的接口的类,客户端必须通过代理与被代理的目标类交互,而代理一般在交互的过程中(交互前后),进行某些特别的处理。
英文定义为:Provide a surrogate or placeholder for another object to control access to it.
代理模式所涉及的角色如下:
抽象主题(Subject)角色:真实主题与代理主题的共同接口。
真实主题(RealSubject)角色:定义了代理角色所代表的真实对象。
代理主题(Proxy)角色: 含有对真实主题角色的引用,代理角色通常在将客户端调用传递给真实主题对象之前或者之后执行某些操作,而不是单纯返回真实的对象。
代理模式深入分析:
代理模式为其他对象提供一种代理以控制对这个对象的访问。在一些情况下客户不想或者不能直接引用一个对象,而代理对象可以在客户和目标对象之间起到中介作用,去掉客户不能看到的内容和服务或者增添客户需要的额外服务。
那么什么时候要使用代理模式呢?在对已有的方法进行使用的时候出现需要对原有方法进行改进或者修改,这时候有两种改进选择:修改原有方法来适应现在的使用方式,或者使用一个“第三者”方法来调用原有的方法并且对方法产生的结果进行一定的控制。第一种方法是明显违背了“对扩展开放、对修改关闭”原则,而且在原来方法中作修改可能使得原来类的功能变得模糊和多元化,而使用第二种方式可以将功能划分的更加清晰,有助于后面的维护。
当然,话又说回来了,如果是一个很小的系统,功能也不是很繁杂,那么使用代理模式可能就显得臃肿,不如第一种方式来的快捷。这就像一个三口之家,家务活全由家庭主妇或者一个保姆来完成是比较合理的,根本不需要雇上好几个保姆层层代理^_^
根据《Java与模式》书中对代理模式的分类,代理模式分为8种,这里将几种常见的、重要的列举如下:
远程(Remote)代理:为一个位于不同的地址空间的对象提供一个局域代表对象。比如:你可以将一个在世界某个角落一台机器通过代理假象成你局域网中的一部分。
虚拟(Virtual)代理:根据需要将一个资源消耗很大或者比较复杂的对象延迟的真正需要时才创建。比如:如果一个很大的图片,需要花费很长时间才能显示出来,那么当这个图片包含在文档中时,使用编辑器或浏览器打开这个文档,这个大图片可能就影响了文档的阅读,这时需要做个图片Proxy来代替真正的图片。
Copy-on-Write代理:虚拟代理的一种。把复制拖延到只有在客户端需要的时候,才真正的采取行动。
保护(Protect or Access)代理:控制对一个对象的访问权限。比如:在论坛中,不同的身份登陆,拥有的权限是不同的,使用代理模式可以控制权限(当然,使用别的方式也可以实现)。
Cache代理:为某一个目标操作的结果提供临时的存储空间,以便多个客户端可以共享这些结果。
防火墙(Firewall)代理:保护目标,不让恶意用户接近。
同步化(Synchronization)代理:使几个用户能够同时使用一个对象而没有冲突。
智能引用(Smart Reference)代理:提供比对目标对象额外的服务。比如:纪录访问的流量(这是个再简单不过的例子),提供一些友情提示等等。
代理模式是一种比较有用的模式,能够协调调用者和被调用者,能够在一定程度上降低系统的耦合度。
Java动态代理类位于Java.lang.reflect包下,一般主要涉及到以下两个类:
(1). Interface InvocationHandler:该接口中仅定义了一个方法Object:invoke(Object obj,Method method, Object[] args)。在实际使用时,第一个参数obj一般是指代理类,method是被代理的方法。这个抽象方法在代理类中动态实现。
(2). Proxy:该类即为动态代理类,其中主要包含以下内容:
Protected Proxy(InvocationHandler h):构造函数。
Static Class getProxyClass (ClassLoader loader, Class[] interfaces):获得一个代理类,其中loader是类装载器,interfaces是真实类所拥有的全部接口的数组。
Static Object newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h):返回代理类的一个实例,返回后的代理类可以当作被代理类使用(可使用被代理类的在Subject接口中声明过的方法)。
所谓Dynamic Proxy是这样一种class:它是在运行时生成的class,在生成它时你必须提供一组interface给它,然后该class就宣称它实现了这些 interface。你当然可以把该class的实例当作这些interface中的任何一个来用。当然啦,这个Dynamic Proxy其实就是一个Proxy,它不会替你作实质性的工作,在生成它的实例时你必须提供一个handler,由它接管实际的工作。
在使用动态代理类时,我们必须实现InvocationHandler接口。通过这种方式,被代理的对象(RealSubject)可以在运行时动态改变,需要控制的接口(Subject接口)可以在运行时改变,控制的方式(DynamicSubject类)也可以动态改变,从而实现了非常灵活的动态代理关系。
代理模式的优缺点分析:
总体而言:使用代理模式能够在不改变原来代码功能的基础上对某一个对象进行额外的控制访问,同时这种分工也体现了单一职责原则。
远程代理:使得系统可以将网络的细节隐藏起来,使得客户端不必考虑网络的存在。
客户完全可以认为代理的对象是局域的而不是远程的,而代理对象承担了大部分的网络通信工作。
虚拟代理:优点是代理对象可以在必要的时候才将被代理的对象加载。代理可以对加载的过程加以必要的优化。当一个模块的加载十分耗费资源的时候,虚拟代理的优点就非常明显。
保护代理:优点是它可以在运行的时间对用户的有关权限进行检查,然后在核实后决定将被调用传递给被代理的对象。
智能引用代理:在访问一个对象时可以执行一些内务处理操作。
代理模式的实际应用简介:
代理模式一般应用于以下情况:
一个比较大的对象,例如说一幅很大的图像,此时需要很长的载入时间。
一个需要很长时间才可以完成的计算结果,并且需要它在计算过程中显示中间结果。
一个存在于远程计算机上的对象,需要通过网络载入这个远程对象就需要很长的时间,特别是在网络传输的高峰期。
用户对对象只有有限的访问权限,此时代理模式可以验证用户的权限。
温馨提示:
在某些情况下,客户不想或者不能直接引用一个对象,这个时候就用到了代理类,代理对象可以再客户和目标对象之间起到中介的作用,客户端分辨不出代理对象与真实对象的区别,代理模式可以不知道真正的代理对象,而仅仅持有一个被代理对象的接口,这时候代理对象不能够创建被代理对象,被代理对象必须有系统的其他角色代为创建并传入。
12,桥接模式
http://www.cnblogs.com/guoshiandroid/archive/2011/06/10/2077971.html
桥接模式解释:
桥接模式(Bridge Pattern)是构造型的设计模式之一。Bridge模式基于类的最小设计原则,通过使用封装,聚合以及继承等行为来让不同的类承担不同的责任。它的主要特点是把抽象(abstraction)与行为实现(implementation)分离开来,从而可以保持各部分的独立性以及应对它们的功能扩展。
英文定义为:Decouple an abstraction from its implementation so that the two can vary independently.
桥接模式的UML图:
代理模式所涉及的角色如下:
抽象化(Abstraction)角色:抽象类接口(接口或者抽象类),并保存一个对实现化对象的引用。
修正抽象化(Refined Abstraction)角色:扩展抽象化角色,改变和修正父类对抽象化的定义。
实现化(Implementor)角色:这个角色给出实现化角色的接口,但不给出具体的实现。必须指出的是,这个接口不一定和抽象化角色的接口定义相同,实际上,这两个接口可以非常不一样。实现化角色应当只给出底层操作,而抽象化角色应当只给出基于底层操作的更高一层的操作。
具体实现化(Concrete Implementor)角色:这个角色给出实现化角色接口的具体实现。
桥接模式深入分析:
一位哲学家说“你永远也看不到一条一模一样的河”,不考虑哲学上的对错,光是从变化的角度看,的确是这样,因为尽管一条小河,在空间上没有发生变化,但在时间坐标上已经发生了改变,世上万物都在做着这样的变化,但是你把一块石头放在你的鱼缸里面,几天后,你会发现它还是那块石头,这说明事物尽管都有向多个维度变化的特性,但是有些事物是相对比较稳定的,而有些事物多维度变化确实比较激励的。我们用继承(inherit)解决了变化不稳定的事物的扩展问题,如何利用面向对象的技术来使得事物能够轻松的沿着多个方向进行变化,实现起来又不是很复杂呢?这就要使用Bridge模式。
Bridge桥接模式是一种结构型模式,它主要应对的是:由于类型的固有罗辑,使得类型具有两个或两个以上的纬度变化。也就是要求抽象不应依赖于实现细节,实现细节应依赖于抽象。
使用桥接模式使得抽象和行为实现分离出来,从而使得他们可以独立自由的修改和扩展。
在面向对象设计的基本概念中,对象这个概念实际是由属性和行为两个部分组成的,我们可以认为属性一种静止的,是一种抽象,一般情况下,行为是包含在一个对象中,但是,在有的情况下,我们需要将这些行为也进行归类,形成一个总的行为接口,这就是桥模式的用处。
我们可以认为桥模式是把一个对象的属性和行为分类开来,然后我们针对属性和行为分别抽象化和具体化,同时保持属性部分对行为的引用。
桥接模式的优缺点分析:
优点:
使用桥模式,能够提供比使用继承关系更灵活的功能。它可以使用抽象和实现分离开,降低了耦合关系。当有新的抽象或实现方式时,只需要继承一个抽象和继承一个实现即可。
缺点:
如果要重新抽象出另外一个类型,则需要修改抽象。
桥接模式的实际应用简介:
桥接模式一般应用于以下场合:
如果一个系统需要在构件的抽象化角色和具体化角色之间增加更多的灵活性,避免在两个层次之间建立静态的联系。
设计要求实现化角色的任何改变不应当影响客户端,或者说实现化角色的改变对客户端是完全透明的。
一个构件有多于一个的抽象化角色和实现化角色,系统需要它们之间进行动态耦合。 虽然在系统中使用继承是没有问题的,但是由于抽象化角色和具体化角色需要独立变化,设计要求需要独立管理这两者。
温馨提示:
桥接模式是一种相对比较复杂的结构型模式,桥接模式把抽象和实现分离开,降低了耦合关系,有利于提高类的可维护性和可复用性。桥接模式把不同的变化纬度分别进行抽象和实现,有利于模块化。
13,组合模式
http://www.cnblogs.com/guoshiandroid/archive/2011/06.html
组合模式解释:
组合模式(Composite Pattern)是构造型的设计模式之一,是指将对象组合成树形结构以表示“部分-整体”的层次结构,组合模式使得客户对单个对象和组合对象的使用具有一致性。
英文定义为:Compose objects into tree structures to represent part-whole hierarchies. Composite lets clients treat individual objects and compositions of objects uniformly.
组合模式的UML图:
组合模式所涉及的角色如下:
抽象组件角色(Component):它为组合中的对象声明接口,也可以为共有接口实现缺省行为。
树叶组件角色(Leaf):在组合中表示叶节点对象没有子节点,实现抽象组件角色声明的接口。
树枝组件角色(Composite):在组合中表示分支节点对象,有子节点,实现抽象组件角色声明的接口;存储子部件。
组合模式深入分析:
将客户代码与复杂的对象容器结构解耦是组合模式的核心思想,解耦之后,客户代码将与纯粹的抽象接口——而非对象容器的复内部实现结构——发生依赖关系,从而更能应对变化。
组合模式中必须提供对子对象的管理方法,不然无法完成对子对象的添加删除等等操作,也就失去了灵活性和扩展性。但是管理方法是在Component中就声明还是在Composite中声明呢?一种方式是在Component里面声明所有的用来管理子类对象的方法,以达到Component接口的最大化。目的就是为了使客户看来在接口层次上树叶和分支没有区别——透明性。但树叶是不存在子类的,因此声明的一些方法对于树叶来说是不适用的。这样也就带来了一些安全性问题。另一种方式就是只在Composite里面声明所有的用来管理子类对象的方法。这样就避免了上一种方式的安全性问题,但是由于叶子和分支有不同的接口,所以又失去了透明性。《设计模式》一书认为:在这一模式中,相对于安全性,我们比较强调透明性。对于第一种方式中叶子节点内不需要的方法可以使用空处理或者异常报告的方式来解决。
组合模式在具体实现中,可以让父对象中的子对象反向追溯;如果父对象有频繁的遍历需求,可使用缓存技巧来改善效率。
组合模式的优缺点分析:
优点:
使客户端调用简单,客户端可以一致的使用组合结构或其中单个对象,用户就不必关系自己处理的是单个对象还是整个组合结构,这就简化了客户端代码。
更容易在组合体内加入对象组件. 客户端不必因为加入了新的对象组件而更改代码。
缺点:
使用组合模式虽然可以更容易的在组合体内加入新的对象组件,带来了很大的灵活性,而且客户端也用户为此修改代码,但是,如果不对新的对象组件加以合理的控制,会构成非常庞大的树形结构,这就会导致在遍历的时候过大的内存开销。
组合模式的实际应用简介:
组合模式适用于以下的情况:
第一:用于表示部分-整体结构
第二:希望客户端忽略组合对象恩和单个对象,客户端将统一的使用组合结构中的所有对象。
同时在使用组合模式的有以下要点:
组合模式采用树形结构来实现普遍存在的对象容器,从而将一对多的关系转化一对一的关系,使得客户代码可以一致地处理对象和对象容器,无需关心处理的是单个的对象,还是组合的对象容器。
将客户代码与复杂的对象容器结构解耦是组合模式的核心思想,解耦之后,客户代码将与纯粹的抽象接口——而非对象容器的复内部实现结构——发生依赖关系,从而更能应对变化。
组合模式中,是将Add和Remove等和对象容器相关的方法定义在;表示抽象对象的Component类中,还是将其定义在表示对象容器的中,是一个关乎透明性和安全性的两难问题,需要仔细权衡。建议才有透明的方式,这里有可能违背面向对象的单一职责原则,但是对于这种特殊结构,这又是必须付出的代价。
组合模式在具体实现中,可以让父对象中的子对象反向追溯;如果父对象有频繁的遍历需求,可使用缓存技巧来改善效率。
温馨提示:
组合模式解耦了客户端程序和复杂元素内部结构,从而使客户端程序可以像处理简单元素一样来处理复杂元素。
在整个对象树中,如果我们经常从子对象获得父对象,尤其是活的根节点的对象,我们可以采用缓存技巧来改善效率。