《Java面向对象程序设计(第2版)第18章.ppt》由会员分享,可在线阅读,更多相关《Java面向对象程序设计(第2版)第18章.ppt(45页珍藏版)》请在淘文阁 - 分享文档赚钱的网站上搜索。
1、设 计 模 式规则面向对象语言语法规则谋略设计模式设计模式含义设计模式(Design pattern)是一套被反复使用、多数人知晓、经过分类编目的代码设计经验的总结。使用设计模式可使代码的重用性、扩展性更好,可靠性更高,更容易被他人理解。模式四个要素 一个助记名,它用一两个词来描述模式的问题、解决方案和效果。描述了应该在何时使用模式。它解释了设计问题和问题存在的前因后果,它可能描述了特定的设计问题,如怎样用对象表示算法等。也可能描述了导致不灵活设计的类或对象结构。有时候,问题部分会包括使用模式必须满足的一系列先决条件。描述了设计的组成成分,它们之间的相互关系及各自的职责和协作方式。因为模式就像
2、一个模板,可应用于多种不同场合,所以解决方案并不描述一个特定而具体的设计或实现,而是提供设计问题的抽象描述和怎样用一个具有一般意义的元素组合(类或对象组合)来解决这个问题。描述了模式应用的效果及使用模式应权衡的问题。模式名称(pattern name)问题(problem)解决方案(solution)效果(consequences)模式设计的原则开闭原则(里氏替换原则、依赖倒转原则):对修改关闭,对扩展开放。组合/聚合复用原则:两种重要的重用手段:Inheritance&composition,能用composition就不用Inheritance。高内聚松耦合原则(接口隔离原则、迪米特法则、
3、单一职责原则):对象之间存在强耦合通常意味着弱内聚,而强内聚的对象通常意味着与其他对象之间存在弱耦合。面向对象设计追求强内聚、弱耦合。模式分类表目的创建型结构型行为型范围类Factory MethodAdapter 类I n t e r p r e t e r Template Method对象Abstract FactoryBuilder Prototype Singleton Adapter 对象Bridge Composite Decorator Facade Flyweight Proxy Chain of ResponsibilityCommand Iterator Mediator
4、 Memento Observer State Strategy Visitor 创建型模式创建型模式Abstract Factory1、问题:系统由不同类型的对象构成,每种类型下又可分为不同型号。系统在建立时,从每种类型中选择一种型号对象进行创建;对于多种组合创建而言,希望能用统一的方式来操作。实现创建具体产品对象的操作用具体工厂创建具体产品对象使用AbstractFactory和AbstractProduct类声明的接口2、解决方案public void creator(AbstractFactor af)/af引用一个具体工厂实例 AbstractProductA a=af.Create
5、ProductA();/产生具体产品A AbstractProductB b=af.CreateProductB();/产生具体产品B .3、效果、效果l优点:AbstractFactory提供了创建组合系统对象的统一接口。当系统扩展时,AbstractProductA、AbstractProductB通过继承关系可扩展出新型号的具体产品,再由AbstractFactory扩展出新具体子类工厂进行对象的组合创建。新具体工厂的实例对象将传递给Client端。由于Client端都是针对抽象工厂和抽象产品进行编程的,因而Client中的代码在传入新工厂实例后不用改动,从而体现了对扩展开放对修改关闭的
6、开闭原则。l缺点:系统如果增加一个新类别产品AbstractProductC时,该模式难以支持;模式没有涉及创建的一组产品如何进行装配的问题。Client端示例代码如下:Builder1、问题问题:构成系统的对象不仅需要创建,而且需要装配,这两个方面如果没有分开,则创建代码和装配代码就紧耦合了。当希望用相同的创建过程产生不同的系统装配效果时,这种紧耦合的设计方式显然不适用。2、解决方案解决方案:有继承的血缘关系,因而A、B、C三个产品都有可能被新产品所替换,而当替换发生时,Director和Client的代码不用做任何修改。l缺点:Director中创建产品A、B、C的“工艺”过程不能改变,也
7、就是说如果工艺过程变为创建A、B或A、B、C、D,则生成器模式不再适用。3、效果、效果l优点:由于创建过程和装配过程分开,因此当有新类型对象需要装配时,新的装配方式将封装在抽象类Builder扩展出的具体子类当中,Director可以依旧通过抽象类Builder的引用向具体Builder对象发送同样的消息。需要说明的是:对于序列图而言,完成的是A、B、C三个产品的装配,这三个产品之间没 Factory Method1、问题:希望对不同类型的创建对象拥有共同的使用方式。3、效果l优点:子类只关心如何实现抽象方法来创建一个具体对象,之后便自动拥有了该对象的扩展功能,即为子类提供一个挂钩以获得对象功
8、能的扩展版本。l缺点:在Creator和Product下容易产生平行类,即每个具体的Creator子类对应产生一个Product下的具体子类对象。2、解决方案Prototype1、问题:当数量稳定的对象可装配成状态多样的组合对象时,如果采用类定义的方式,则会出现类急速增长或平行类现象。2、解决方案l缺点:如果克隆对象本身也是一个组合对象,进行克隆操作时,构件对象是克隆(深拷贝)还是共享需要进行慎重权衡。3、效果l优点:用统一的接口克隆对象,然后装配成组合对象,避免类数量急速增长和平行类问题产生的同时,也体现了开闭原则;另外,组合对象是由克隆的对象装配而成,这意味着各组合对象之间彼此状态是相互独
9、立的。Singleton1、问题:当对象占有大量的计算机资源时,希望类的对象有且只有一个;当一个对象不掌握另一对象的引用,然而希望在必要时能够向其发送消息。3、效果l优点:保证一个类仅有一个实例;提供对某个对象的全局访问点(在程序的任意地方,通过类的静态方法得到对象引用)。l缺点:只考虑了对象创建的管理,没有考虑销毁的管理,另外也不支持对象序列化。2、解决方案结构型模式结构型模式Adapter模式1、问题:已经编码完成的系统需要同其他系统进行协作,替换现有系统的部分功能,但现有系统被替换功能的使用端代码不能更换,需要协作的系统调用接口也不能更换,从而造成协作困难。2、解决方案(b)类适配器)类
10、适配器(C)对象适配器)对象适配器3、效果l优点:使两个异构系统能够彼此调用;对象适配器比类适配器更灵活。l缺点:类适配器对只具有单一继承特点的语言例如Java不适用。(a)串口)串口USB适配器适配器Bridge模式1.问题:在抽象类的派生体系当中,如果既定义了具有功能使用逻辑的抽象方法,又定义了功能实现的抽象方法,这种结构会因二者组合变化让派生类数目激增。推而广之,如果一个抽象类具有二维变化特性,这将导致派生类数目的激增。2.解决方案3.效果l优点:将功能的使用和实现两种抽象定义分开,变继承方式为关联组合方式,从而使它们都可以独立变化,可以在程序运行时刻对它们进行选择、切换和组合,系统的结
11、构层次也更清晰。l缺点:功能实现通过继承抽象类Windowimp来进行,这种方式灵活性不够。因为功能实现往往需要扩充,从而引起Windowimp接口的变化。.Composite模式1、问题:一个组合对象往往由若干构件对象组成,并且一个组合对象又有可能是另一组合对象的构件;另外,组合对象和构件对象在功能执行上没有差别。2、解决方案典型的composite对象结构3、效果l优点:易于表达具有递归特点的树形层次结构的系统,并且结构中的每个对象的操作方法都一致,从而简化客户端代码的编写。l缺点:加入Composite中的所有对象出现同质化现象,即所有对象都只能从Component角度去认识,因而Com
12、ponent的任何改变将会扩散到整个结构当中。Decorator1、问题:对一个对象添加额外的装饰,但如果装饰的组合方式较多,采用类定义的方式表达装饰效果,则类的数量会激增。2、解决方案 ConcreteComponentConcreteDecorateAComponentConcreteDecorateBComponentConcreteComponentConcreteDecorateAComponent3、效果l优点:很容易为需要装饰的类添加装饰,看起来好像定义了新类,并且装饰方式可以自由组合;装饰对象和需要装饰的对象具有共同的操作接口。l缺点:与组成模式类似。Facade模式1、问题:
13、客户端使用一个复杂子系统功能时,如果是针对子系统中的每个类的接口进行调用,则会与子系统形成复杂的耦合关系。2、解决方案3、效果l优点:为子系统提供一致的访问入口,这个入口使得这一子系统更加容易使用,并且屏蔽了子系统内部的复杂逻辑,从而实现了子系统和客户端代码的弱耦合。l缺点:Facade有可能变为胖接口而与接口隔离原则相悖。FlyWeight(享元)模式1、问题:一个系统出现大量的细粒度对象,这些细粒度对象会造成系统内存开销的浪费和对象维护的困难。2、解决方案3、效果l优点:可大大降低内存中对象的数量,或者在不降低对象数量的前提下降低内存的占用,例如案例1中,CatalogueEntry对象就
14、可看成Part对象的享元。外部状态可以存储也可计算,如果采用计算方式,对内存的节约效果最好,即用计算时间来换取内存存储。l缺点:模式允许客户端直接对具体类进行编程,这与开闭原则在一定程度上相悖。Proxy1、问题:在一些情况下,客户端与要访问的目标对象之间建立一个代理对象,客户端通过代理来访问目标对象。代理有远程代理、虚代理、保护代理、智能指引等类型。远程代理负责同远端目标对象进行通信,客户端则直接访问本机的远程代理;虚代理在当真正创建开销很大的目标对象前,可起到临时替身的作用;保护代理用来对目标对象的访问进行权限检查;智能指引取代了简单指针,它在访问目标对象前执行一些诸如引用计数等附加操作。
15、对于使用代理的客户端而言,如何做到对代理和目标对象的访问效果一致就是需要解决的问题。2、解决方案 3、效果l优点:远程代理隐藏一个对象处于不同地址空间的事实;虚代理不需要创建和装载所有的对象,因此加速了应用程序的启动;保护代理和智能指引则可以有一些附加的内务操作;另外,对于开发人员而言,代理的引入简化了编程的复杂度。l缺点:代理毕竟不是目标对象,如果目标对象变化后,代理也需要更新。如果代理数量多且部署分散,则更新困难。行为型模式行为型模式Chain of Responsibility(职责链)1、问题:一个消息请求可能被多个接收对象处理,同时一个接收者也可以对应多个消息发送者。如何使消息的发送
16、者和接收者的耦合关系变得灵活,即请求的发送者不需要指定具体的接收者,让请求的接收者自身在运行时决定是否处理请求,就是应该解决的主要问题。2、解决方案解决方案:3、效果l优点:解除了发送者和接收者的直接耦合;可以动态地对链进行增加和修改以改变处理一个请求的职责。l缺点:请求在链中不能保证一定被处理。Command模式1、问题:在软件系统中,命令的调用者与接收者通常直接耦合。但在某些情况下,如对命令需要进行记录、撤销等处理,这种直接耦合将无法满足要求。2、解决方案3、效果。l优点:将命令发送者和接收者解耦,记录它们之间的行为交互;有新的命令对象时,扩展抽象类Command具体子类,且Invoker
17、不用进行任何改动就可和新的Receiver对象进行耦合;如果和Composite模式结合,则可装配成为一个复合命令,可以与更多的接收者进行动态耦合。l缺点:可能会产生数量较大的命令类。Interpreter模式1、问题:经常发生的一类问题易于理解和定义,则可用语言来表示,因而需要建立语法解释器来解释语言中的句子。2、解决方案3、效果l在易于实现语法解释的同时,也易于通过类的继承来扩展语法。l缺点:表达复杂的语法会使类数量变得庞大。Iterator模式1.问题:不同类型集合对象的内部结构不尽相同,对它们进行遍历会因结构的不同而导致算法不同,这样就对客户端遍历操作带来不便。2.解决方案3.效果l优
18、点:在不暴露Aggregate内部结构的情况下,用统一的Iterator对其结构不同的各种子类进行遍历;另外Aggregate可分别创建多种Iterator子类实例,这样就可对一种集合对象采用多种方法进行遍历。l缺点:迭代得到的对象引用将失去类型特征,必须进行相应的类型转化;遍历顺序常给人以集合对象内部存储结构顺序的错觉。Mediator模式1、问题:随着系统中对象数量的增多,系统对象之间的耦合关系也会越来越复杂,如何降低系统对象间的耦合度就是需要解决的问题。Mediator2、解决方案3、效果l优点:中间者模式将Colleague之间的强耦合变为弱耦合,这样就可独立地改变和复用各自的Coll
19、eague类和Mediator类。Colleague与Mediator之间是抽象耦合,Colleague不知道其所通信的Mediator究竟是哪个具体类,因而无论哪个继承层次的Colleague对象都可向Mediator对象发送消息,进而Colleague任意继承层次的类对象之间都可以进行相互通信;Mediator将原本分布于多个对象间的行为集中起来,改变这些行为只需要产生Mediator的子类即可。l缺点:中介者模式将交互的复杂性变为中介者的复杂性,这有可能使得中介者自身成为一个难以维护的庞然大物。Memento模式1、问题:称为原发器的对象常需要将内部的状态保存到外部的管理对象当中,形成具
20、有历史记录的备忘录,必要时(例如执行Undo命令)可恢复原发器的状态,这个过程必须解决备忘录信息对管理者屏蔽而对原发器开放的问题。Undo3、效果l优点:使用备忘录可以避免暴露一些只应由原发器管理却又必须存储在原发器之外的信息。l缺点:如果原发器内部状态过多,拷贝到备忘录中的信息可能过大,导致代价过高;另外维护备忘录也有开销过大的潜在问题。2、解决方案Observer模式问题:数据与表现形式是两个不同的概念,它们的关系可以用目标和观察者来说明。一个目标可以对应多个观察者,将目标和观察者分开有利于系统的设计,因为多个观察者可以共享一个目标。目标变化了,观察者也应变化,这样,目标如何保持与众多观察
21、者数据状态的同步以及众多观察者之间的数据状态如何同步就是应该着重解决的问题。图中,subject代表数据对象,它有三个observers对象,分别用表格、柱状图、饼图来展现subject中的数据。改变表格中的数据时,也就是改变了subject中的数据,之后柱状图和饼图对象收到通知,到subject中取回最新数据并进行界面刷新。如果站在observers的角度看,就实现了它们之间的数据状态同步。subject与observers这种交互关系也称为发布订阅,目标是通知的发布者,它发出通知时并不需要知道谁是它的观察者,可以有任意数目的观察者订阅并接收通知。2、解决方案3、效果l优点:Subject和
22、Observer各自可以独立变化,因而当观察者类型增加或要求变更时,Subject可以不受影响,反之亦然;另外当目标状态变化时,目标就以广播通信的方式通知各观察者,各观察者的数据状态因此可以保持同步,另外对消息是否进行处理取决于各观察者自身。l缺点:一个观察者可能不知道另一个观察者的存在,它对目标的错误改变有可能殃及其他的观察者,造成其他观察者错误的更新。State模式1、问题:对象的状态决定对象的行为,对象状态变化后,其行为也相应变化,通常采用条件语句来实现。例如当对象扩展出一个新状态后,增加一条case语句,case下放置行为代码,这样的设计违背了开闭原则。2、解决方案3、效果l优点:状态
23、对象化后,如果Context出现新的状态,可对State扩展出具体子类,而Context中的代码不用修改,体现了开闭原则。l缺点:如果Context的状态过多,则会造成State具体类过多。class Context void request(State s)s.handle();class Context void request()switch(a)case 1:System.out.println(1);break;case 2:System.out.println(2);break;a的取值可能因为需要不断变化,所以case语句也需要不断增加,从而Context类不断更改。abstra
24、ct class State abstract void handle();class State1 extends State void handle()System.out.prinln(1);class State2 extends State void handle()System.out.prinln(2);:state2:state1:staten当状态增加时,只需产生具体的state的子类,Context的request中的代码不用调整Context代码稳定的同时,其内部状态可以不断扩展,并且行为也发生改变,这是在没有修改类Context的条件下完成的。Context的稳定保证了
25、发布出去的软件版本的稳定,扩展的具体子类则包含在新的版本中。Class Context State current;void setState(State s)current=s;void request()if(current!=null)current.handle();current.goNext(this);当Context的状态具有不断切换的要求下,可设计为:abstract class State abstract void handle();abstract void goNext(Context ct);class State1 extends State void handl
26、e()System.out.prinln(1);void goNext(Context ct)ct.setState(new state2();Context中保留当前状态对象引用,当request()事件发生时,完成相应的功能调用外,也完成状态转化。Context ct=new Context();State s =new State1();ct.setState(s);ct.request();Client端代码Strategy模式1、问题:程序设计中的算法需要更新,当这种更新需要改变现有系统编码时,必然违反开闭原则;另外,不同的算法各有优点,这样可能形成一系列算法,在程序运行时刻需要进行
27、动态选择。2、解决方案3、效果:与状态模式效果类似。模板方法(Template Method)1.问题:算法可能因为某些步骤的不同而形成多个版本,这就需要处理一系列版本算法中的共性和个性关系,并在程序运行时可动态替换。2.解决方案3、效果l优点:子类对抽象方法给出实现就拥有了整个算法的功能。l缺点:算法骨架稳定很重要,否则模板方法失效。1、问题:对具有集合结构的类的遍历访问,最终会转化为对类中各元素的访问,每种遍历算法因而都是对各元素访问的方法集合。如果集合结构类很稳定,类中的元素也很稳定,但遍历算法经常变化;如果遍历算法定义在集合结构类当中,则集合结构类也会经常变化,因而需要解决既要保持集合结构类的稳定又可对集合结构类中元素能不断更换遍历算法的问题。2、解决方案Visitor模式3、效果l优点:只需在抽象类Visitor下派生出一个具体子类就可为集合结构类ObjectStructure增加一个新的遍历算法;Visitor对Element对象的访问方法各异,这与Iterator采用相同的方法访问集合对象有着明显的不同。l缺点:ObjectStructure中增加一个新类型的结构元素(即Element扩展出一个新的具体子类)很困难,因为这意味着抽象类Visitor中必须增加一个抽象接口,从而破坏了Visitor的稳定性。模模式式全全家家福福
限制150内