1、设计模式(2),Design Pattern (2),2018/9/21,Institute of Computer SoftwareNanjing University,1,摘要,Design PatternsWhy, What, HowCreational, Structural and Behavioral Patterns,2018/9/21,Institute of Computer SoftwareNanjing University,2,Structural Patterns,结构模式描述如何将类或者对象结合在一起形成更大的结构。类的结构模式:结构型类模式使用继承机制来组合接口或
2、实现。对象的结构模式:结构型对象模式描述了如何对一些对象进行组合,从而实现新功能的一些方法。可以在运行时刻改变对象组合关系。,2018/9/21,Institute of Computer SoftwareNanjing University,3,Structural Patterns,Adapter Bridge Composite Decorator Facade Flyweight Proxy,2018/9/21,Institute of Computer SoftwareNanjing University,4,Adapter,Aliases:WrapperIntent将一个类的接口转
3、换成客户希望的另外一个接口。Adapter模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作Motivation有时为复用而设计的工具箱类不能够被复用的原因仅仅是因为它的接口与专业应用领域所需要的接口不匹配,2018/9/21,Institute of Computer SoftwareNanjing University,5,Example,2018/9/21,Institute of Computer SoftwareNanjing University,6,adapter,adaptee,target,Applicability,Use the Adapter pattern
4、when你想使用一个已经存在的类,而它的接口不符合你的需求。你想创建一个可以复用的类,该类可以与其它不相关的类或不可预见的类(即那些接口可能不一定兼容的类)协同工作。(仅适用于对象Adapter)你想使用一些已经存在的类,但是不可能对每一个都进行子类化以匹配它们的接口。对象适配器可以适配它的父类接口。,2018/9/21,Institute of Computer SoftwareNanjing University,7,Structure,2018/9/21,Institute of Computer SoftwareNanjing University,8,类适配器,对象适配器,Parti
5、cipants,Target定义Client使用的与特定领域相关的接口Client与符合Target接口的对象协同Adaptee定义一个已经存在的接口,这个接口需要适配Adapter对Adaptee的接口与Target的接口进行适配,2018/9/21,Institute of Computer SoftwareNanjing University,9,Collaboration,Client在Adapter实例上调用一些操作,接着适配器调用Adaptee的操作实现这个请求。,2018/9/21,Institute of Computer SoftwareNanjing University,
6、10,Sample Code,Consequences,本质上是两种重用模型class adapter:无法适配adaptee以及所有它的子类,但是可以重载adaptee的行为object adapter可以适配adaptee的所有子类,但重定义adaptee的行为比较困难Adapter的匹配精度:Adapter的工作量取决于Target接口与Adaptee接口的相似程度Pluggable Adapters:具有内部接口适配的类,2018/9/21,Institute of Computer SoftwareNanjing University,11,Consequences,使用双向适配器提
7、供透明操作针对class adapter,用多重继承来实现,2018/9/21,Institute of Computer SoftwareNanjing University,12,Implementation,使用继承机制实现class adapter使用内嵌对象技术实现object adapterPluggable Adapters使用抽象操作使用代理对象参数化的适配器:reflection技术,2018/9/21,Institute of Computer SoftwareNanjing University,13,Related Patterns,Bridge:结构类似,但Bridg
8、e的目的是将接口部分和实现部分分离,从而使得它们可以较为容易也相对独立的加以改变。而adapter则意味着改变一个已有对象的接口Decorator:增强了其它对象的功能而同时又不改变它的接口,透明性比adapter好Proxy:在不改变它的接口的条件下,为另一个对象定义了一个代理。,2018/9/21,Institute of Computer SoftwareNanjing University,14,增:Default Adapter,适配器模式的特例!缺省适配模式为一个接口提供缺省实现,这样子类型可以从这个缺省实现进行扩展,而不必从原有接口扩展。MotivationJava中有着特殊的应
9、用java.awt.event.WindowAdapter,2018/9/21,Institute of Computer SoftwareNanjing University,15,Example,interface 和尚 public void 吃斋(); public void 念经(); public void 打坐(); public void 撞钟(); public void 习武(); public String getName();,2018/9/21,Institute of Computer SoftwareNanjing University,16,class 鲁智深
10、implements 和尚 public void 习武() 拳打镇关西;大闹五台山; public String getName() return “鲁智深”;,Compilation Error!,abstract class 天星 implements和尚 public void 吃斋(); public void 念经(); public void 打坐(); public void 撞钟(); public void 习武(); public String getName()return null;,class 鲁智深 extends 天星 public void 习武() 拳打镇关
11、西;大闹五台山; public String getName() return “鲁智深”;,Compilation Passed!,Adapter!,Applicability,如果不准备实现一个接口的所有方法时,可以制造一个抽象类,给出所有方法的平庸的具体实现适配器模式把一个类的接口变换成客户端所期待的另一种接口,适配器模式的“平庸化”形式可以使所考察的类不必实现不需要的那部分接口。,2018/9/21,Institute of Computer SoftwareNanjing University,17,Structure,2018/9/21,Institute of Computer
12、SoftwareNanjing University,18,ServiceAdapter应当是抽象类,但它所提供的方法却应当是具体的方法,而不是抽象的方法提供默认实现。具体子类可以按照需要只实现需要实现的方法,忽略不需要实现的方法。,Sample Code,Bridge,Aliases:Handle/BodyIntent将抽象部分与它的实现部分分离,使它们都可以独立地变化Motivation要做到“抽象(接口)与实现分离”,最常用的办法是定义一个抽象类,然后在子类中提供实现。也就是说,用继承机制达到“抽象(接口)与实现分离”但是这种方法不够灵活,继承机制把实现与抽象部分永久地绑定起来,要想独立
13、地修改、扩展、重用抽象(接口)与实现都非常困难。回顾下OCP和CARP原则,2018/9/21,Institute of Computer SoftwareNanjing University,19,Example,2018/9/21,Institute of Computer SoftwareNanjing University,20,扩展Window抽象使之用于不同种类的窗口或新的平台很不方便,继承机制使得客户代码与平台相关,Example,2018/9/21,Institute of Computer SoftwareNanjing University,21,将Window抽象和它的实
14、现部分分别放在独立的类层次结构中,针对窗口接口,针对平台的窗口实现,对“变化”的封装,2018/9/21,Institute of Computer SoftwareNanjing University,22,抽象化,实现化,Abstraction,Implementation,需要变化,需要变化,Bridge!,Applicability,编译时刻无法确定抽象(接口)与实现之间的关系抽象部分与实现部分都可以通过子类化而扩展对一个实现的修改不影响客户(无须重新编译)在C+中,对客户完全隐瞒实现细节因为扩展的原因,需要把一个类分成两部分,(以便灵活组合)在多个对象之间共享数据,但客户不需要知道,
15、2018/9/21,Institute of Computer SoftwareNanjing University,23,Structure,2018/9/21,Institute of Computer SoftwareNanjing University,24,Participants,Abstraction定义抽象类的接口维护一个指向Implementor类型对象的指针RefinedAbstraction扩充由Abstraction定义的接口Implementor定义实现类的接口,不一定要与Abstraction的接口完全一致,甚至可以完全不同ConcreteImplementor实现
16、Implementor接口并定义它的具体实现,2018/9/21,Institute of Computer SoftwareNanjing University,25,Collaborations,Abstraction将Client的请求转发给它的Implementor对象,2018/9/21,Institute of Computer SoftwareNanjing University,26,Sample Code,Consequences,分离接口及其实现部分。抽象类的实现可以在运行时刻进行配置,一个对象甚至可以在运行时刻改变它的实现提高可扩充性:抽象与实现两部分可以单独扩充实现细节
17、对客户透明,2018/9/21,Institute of Computer SoftwareNanjing University,27,Implementation,仅有一个Implementor则没有必要创建一个抽象的Implementor - 退化创建正确的Implementor对象根据客户环境,或者通过factory (回顾Abstract Factory)共享implementors资源管理:引用计数技术采用多继承机制,依赖于静态继承, 不好,2018/9/21,Institute of Computer SoftwareNanjing University,28,Related Pa
18、tterns,Abstract Factory可以用来创建和配置Bridge模式与Adapter模式的区别Adapter模式用来帮助无关的类协同工作,通常在系统设计完成后才会被使用Bridge模式则在系统开始时就被使用,它使得抽象接口和实现部分可以独立进行改变,2018/9/21,Institute of Computer SoftwareNanjing University,29,思考题:JDBC/ODBC桥梁是Bridge模式吗?,Composite,Intent将对象组合成树形结构以表示“部分-整体”的层次结构,Composite使得用户对单个对象和组合对象的使用具有一致性。Motiva
19、tion一些部件对象经过组合构成的复合部件对象仍然具有单个部件对象的接口,这样的复合部件对象被称为“容器(container)”复合部件与单个部件具有同样的接口,所有接口包含两部分:单个部件的功能、管理子部件的功能递归组合,2018/9/21,Institute of Computer SoftwareNanjing University,30,Example,2018/9/21,Institute of Computer SoftwareNanjing University,31,Applicability,想表示对象的“部分-整体”层次结构希望用户忽略组合对象与单个对象的不同,用户将统一地
20、使用组合结构中的所有对象,2018/9/21,Institute of Computer SoftwareNanjing University,32,Structure,2018/9/21,Institute of Computer SoftwareNanjing University,33,Participants,Component为组合中的对象声明接口在适当的情况下实现所有类共有接口的缺省行为声明一个接口用于访问和管理Component的子组件(可选)在递归结构中定义一个接口,用于访问一个父部件,并在合适的情况下实现它。Leaf在组合中表示叶节点对象,没有子节点在组合中定义图元对象的行为
21、Composite定义有子部件的那些部件的行为存储子部件在Component接口中实现与子部件有关的操作Client通过Component接口操纵组合部件的对象,2018/9/21,Institute of Computer SoftwareNanjing University,34,Collaborations,用户使用Component类接口与组合结构中的对象进行交互。如果接收者是一个叶节点,则直接处理请求。如果接收者是Composite,它通常将请求发送给它的子部件,在转发请求之前与/或之后可能执行一些辅助操作。,2018/9/21,Institute of Computer Softw
22、areNanjing University,35,Sample Code,Consequences,定义了包含leaf对象和composite对象的类层次接口。 递归结构简化客户代码,客户一致地处理复合对象和单个对象使得更容易增加新类型的组件,易于增加新类型的组件使设计变得更加一般化,无法限制类型的组合,可以在运行时刻通过类型检查加以弥补,2018/9/21,Institute of Computer SoftwareNanjing University,36,Implementation,显式的父对象的引用,在子对象中给出父对象的引用,可以很容易地遍历所有的父对象共享组件:当一个组件只有一个
23、父部件时,很难共享最大化Component接口?声明管理子部件的操作:在安全性和透明性之间权衡Component是否应该实现一个Component列表? 子部件排序使用高速缓存存储改善性能应该由谁删除Component存储组件最好用哪一种数据结构: List, Array, HashMap?,2018/9/21,Institute of Computer SoftwareNanjing University,37,Related Patterns,Decorator经常和Composite一起使用,通常有一个公共的父类Flyweight可以共享组件但是不再能引用他们的父类对象Iterator:
24、可用来遍历CompositeVisitor:将本来应该分布在Composite和Leaf类中的操作和行为局部化,2018/9/21,Institute of Computer SoftwareNanjing University,38,思考题:考虑如何实现安全方式的Composite,Decorator,Aliases: WrapperIntent动态地给一个对象添加一些额外的职责。就增加功能来说,Decorator模式相比生成子类更为灵活动机希望给某个对象而不是整个类添加一些功能,2018/9/21,Institute of Computer SoftwareNanjing Universi
25、ty,39,Example,2018/9/21,Institute of Computer SoftwareNanjing University,40,Example,2018/9/21,Institute of Computer SoftwareNanjing University,41,Applicability,在不影响其他对象的情况下,以动态、透明的方式给单个对象添加职责处理那些可以撤销的职责当不能采用生成子类的方法进行扩充时可能有大量独立的扩展,为支持每一种组合将产生大量的子类类定义被隐藏或者类定义不能用于生成子类,2018/9/21,Institute of Computer So
26、ftwareNanjing University,42,Structure,2018/9/21,Institute of Computer SoftwareNanjing University,43,Participants,Component定义一个对象接口,可以给这些对象动态地添加职责ConcreteComponent定义一个对象,可以给这个对象添加一些职责Decorator维持一个指向Component对象的指针,并定义一个与Component接口一致的接口ConcreteDecorator向组件添加职责,2018/9/21,Institute of Computer SoftwareN
27、anjing University,44,Collaboration,Decorator将请求转发给它的Component对象,并有可能在转发请求前后执行一些附加的动作。,2018/9/21,Institute of Computer SoftwareNanjing University,45,Sample Code,New Decorator1( new Decorator2 ( new Decorator3 ( new ConcreteComponent(),ConcreteComponent,Decorator1,Decorator2,Decorator3,思考题:查看Java IO包,
28、思考其中所使用的设计模式,包裹图,Consequence,优点比静态继承更灵活避免在层次结构高层的类有太多的特征缺点Decorator与它的Component不一样,使用装饰时不应该依赖对象标识有许多小对象,2018/9/21,Institute of Computer SoftwareNanjing University,46,Implementation,接口的一致性,装饰对象的接口必须与它所装饰的Component的接口是一致的当仅需要添加一个职责时可以省略抽象的Decorator类保持Component类的简单性改变对象外壳与改变对象内壳的区别,结合Strategy模式,2018/9/
29、21,Institute of Computer SoftwareNanjing University,47,Related Patterns,Adapter:Decorator模式中装饰仅改变对象的职责而不改变它的接口,而Adapter模式中适配器将给对象一个全新的接口Composite:可以将装饰视为一个退化的仅有一个组件的组合,Decorator的目的不在于对象聚集Strategy:用一个装饰可以改变对象的外表,而Strategy模式可以改变对象的内核,2018/9/21,Institute of Computer SoftwareNanjing University,48,Facade
30、,Intent为子系统中的一组接口提供一个一致的界面,Facade模式定义了一个高层接口,这个接口使这一子系统更加容易使用Motivation使系统的各子系统之间的关联最小,引入一个facade对象,为子系统提供一个简单的、泛化的设施,2018/9/21,Institute of Computer SoftwareNanjing University,49,Example,2018/9/21,Institute of Computer SoftwareNanjing University,50,Applicability,为一个复杂的子系统提供一个简单接口。子系统往往会非常复杂,但是其接口应该
31、尽可能地简单,特别是对于一般用户而言客户与实现抽象功能的诸类之间存在一定的依赖性,facade可以降低这种依赖性在多个子系统的结构中,使用facade模式定义子系统的入口点,有助于降低各子系统之间的依赖性,2018/9/21,Institute of Computer SoftwareNanjing University,51,Structure,2018/9/21,Institute of Computer SoftwareNanjing University,52,Participants,Facade知道哪些子系统类负责处理请求将客户的请求代理给适当的子系统对象Subsystem cla
32、sses实现子系统的功能处理由Facade对象指派的任务没有facade的任何相关信息;即没有指向facade的指针,2018/9/21,Institute of Computer SoftwareNanjing University,53,Collaborations,客户程序通过发送请求给Facade的方式与子系统通讯,Facade将这些消息转发给适当的子系统对象使用Facade的客户程序不需要直接访问子系统对象,2018/9/21,Institute of Computer SoftwareNanjing University,54,Sample Code,Consequences,它对
33、客户屏蔽子系统组件,因而减少了客户处理的对象的数目并使得子系统使用起来更加方便它实现了子系统与客户之间的松耦合关系,而子系统内部的功能组件往往是紧耦合的。化“紧耦合”为“松耦合” 实现组件软件的关键技术并不限制应用使用子系统类,2018/9/21,Institute of Computer SoftwareNanjing University,55,Implementation,降低客户-子系统之间的耦合度,用抽象类实现Facade而它的具体子类对应于不同的子系统实现可以进一步解耦;另一种方法是用不同的子系统对象配置Facade对象公共子系统类与私有子系统类,2018/9/21,Institu
34、te of Computer SoftwareNanjing University,56,Related Patterns,Abstract Factory模式可以与Facade模式一起使用以提供一个接口,这一接口可用来以一种子系统独立的方式创建子系统对象Mediator模式与Facade模式的相似之处是,它抽象了一些已有的类的功能通常仅需要一个Facade对象,因此可以用Singleton模式,2018/9/21,Institute of Computer SoftwareNanjing University,57,Flyweight,Intent运用共享技术有效支持大量细粒度的对象。Mot
35、ivation当对象的粒度太小的时候,大量对象将会产生巨大的资源消耗,因此考虑用共享对象(flyweight)来实现逻辑上的大量对象。Flyweight对象可用于不同的context中,本身固有的状态(内部状态)不随context发生变化,而其他的状态(外部状态)随context而变化Flyweight模式对那些通常因为数量太大而难以用对象来表示的概念或实体进行建模,2018/9/21,Institute of Computer SoftwareNanjing University,58,Example,2018/9/21,Institute of Computer SoftwareNanji
36、ng University,59,Example,2018/9/21,Institute of Computer SoftwareNanjing University,60,外部状态,作为参量传入,Flyweight对象,Applicability,一个应用程序使用了大量的对象完全由于使用大量的对象,造成很大的存储开销对象的大多数状态都可变为外部状态如果删除对象的外部状态,那么可以用相对较少的共享对象取代很多组对象应用程序不依赖于对象标识,2018/9/21,Institute of Computer SoftwareNanjing University,61,Structure,2018/9
37、/21,Institute of Computer SoftwareNanjing University,62,Structure,Object graph,2018/9/21,Institute of Computer SoftwareNanjing University,63,Sample Code,Participants,Flyweight描述一个接口,通过这个接口flyweight可以接受并作用于外部状态ConcreteFlyweight实现Flyweight接口,并为内部状态增加存储空间。必须是可以共享的,存储的状态必须是内部的。UnsharedConcreteFlyweight不
38、强制共享FlyweightFactory创建并管理flyweight对象确保合理地共享flyweight,提供已创建的flyweight实例或者创建一个(如果不存在的话)Client维持一个对flyweight的引用计算或存储一个(多个)flyweight的外部状态,2018/9/21,Institute of Computer SoftwareNanjing University,64,Collaboration,Flyweight执行时所需的状态必定是内部或外部的。内部状态存储在ConcreteFlyweight中,外部对象则由Client对象存储或计算。当用户调用flyweight对象的
39、操作时,将该状态传递给它用户不应直接对ConcreteFlyweight类进行实例化,而只能从FlyweightFactory对象得到ConcreteFlyweight对象,以保证对它们适当地进行共享,2018/9/21,Institute of Computer SoftwareNanjing University,65,Consequences,把对象的状态分开:intrinsic and extrinsic 节约存储空间:内部状态的共享节约了大量空间,外部状态可通过计算获得从而进一步节约空间Flyweight与Composite结合,形成一个共享叶节点的图。,2018/9/21,Inst
40、itute of Computer SoftwareNanjing University,66,Implementation,删除外部状态:理想情况是,外部状态可以由一个单独的对象结构计算得到,且该结构的存储要求非常小管理共享对象,客户不能直接实例化flyweight,必须通过管理器,例如FlyweightFactory。,2018/9/21,Institute of Computer SoftwareNanjing University,67,Related Patterns,与Composite模式结合起来,用共享叶节点的有向无环图实现一个逻辑上的层次结构最好用Flyweight实现Sta
41、te和Strategy对象,2018/9/21,Institute of Computer SoftwareNanjing University,68,Proxy,Aliases:SurrogateIntent为其它对象提供一种代理以控制对这个对象的访问Motivation对于每一个开销很大的对象,应该根据需要进行创建,2018/9/21,Institute of Computer SoftwareNanjing University,69,Example,2018/9/21,Institute of Computer SoftwareNanjing University,70,Applica
42、bility,在需要用比较通用和复杂的对象指针代替简单的指针时使用Proxy模式Remote Proxy:为一个对象在不同的地址空间提供局部代表Virtual Proxy:根据需要创建开销很大的对象Protection Proxy:控制对原始对象的访问,用于对象应该有不同访问权限的时候Smart Reference:取代了简单的指针,在访问对象时执行一些附加操作引用计数,加锁,将第一次引用的持久对象装入内存,2018/9/21,Institute of Computer SoftwareNanjing University,71,Structure,2018/9/21,Institute of
43、 Computer SoftwareNanjing University,72,不改变主题接口,不让客户端感觉到代理的存在,将客户端的调用委派给真实的主题对象,传递请求之前/之后都可以执行特定的操作,而不是单纯传递请求,Participants,Proxy保存一个引用使得proxy可以访问实体提供一个与Subject的接口相同的接口,这样proxy就可以用来代替实体控制对实体的存取,并可能负责创建和删除它Subject定义RealSubject和Proxy的共同接口RealSubject定义Proxy所代表的实体,2018/9/21,Institute of Computer Software
44、Nanjing University,73,Collaboration,Proxy根据其种类,在适当的时候向RealSubject转发请求,2018/9/21,Institute of Computer SoftwareNanjing University,74,Sample Code,Consequences,Proxy模式在访问对象时引入了一定程度的间接性Remote proxy可以隐藏一个对象存在于不同地址空间的事实Virtual proxy可以进行最优化Protection Proxy和Smart Reference都允许在访问一个对象时有一些附加的内务处理可以对用户隐藏一种copy-
45、on-write的优化方式,该优化与根据需要创建对象有关,2018/9/21,Institute of Computer SoftwareNanjing University,75,Implementation,语言特性C+:重载存取运算符Smalltalk:使用doesNotUnderstandProxy并不总需要知道实体的类型,2018/9/21,Institute of Computer SoftwareNanjing University,76,Related Patterns,Adapter模式中适配器为它所适配的对象提供了一个不同的接口,而Proxy则提供了与它的实体相同的接口,或
46、其接口的子集(Protection Proxy可能会拒绝执行实体的操作)Decorator的实现和Proxy类似,但目的不同:Decorator对象添加一个或多个功能,而Proxy则控制对对象的访问,2018/9/21,Institute of Computer SoftwareNanjing University,77,Summary:Structural Patterns,Adapter 、Bridge、FacadeAdapter用于两个已有的不兼容接口之间的转接Bridge用于将一个抽象与多个可能的实现进行桥接Facade用于为复杂的子系统定义一个新的简单易用的接口Composite、D
47、ecorator和ProxyComposite用于构造对象(递归)组合结构Decorator用于为对象增加新的职责Proxy为目标对象提供一个替代者Flyweight针对细粒度对象的一种全局控制手段,2018/9/21,Institute of Computer SoftwareNanjing University,78,作业,比较Adapter,Bridge和Facade的相似点与不同点比较Composite,Decorator和Proxy的相似点与不同点学习Java2.0对代理模式的支持介绍java.lang.reflect.Proxy, java.lang.reflect.InvocationHandler的使用,2018/9/21,Institute of Computer SoftwareNanjing University,79,