高级软件工程之设计模式_第1页
高级软件工程之设计模式_第2页
高级软件工程之设计模式_第3页
高级软件工程之设计模式_第4页
高级软件工程之设计模式_第5页
已阅读5页,还剩133页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、-2-设计?设计?-3-设计模式?设计模式?-4-设计模式的基本要素设计模式的基本要素n1. 名称:用于助记,形象表示这个模式n2. 问题:这个模式可以解决什么问题n3. 解决方案:这个模式怎样解决这个问题的步骤与方法n4. 效果:使用这个模式与不使用这个模式有什么区别,它有什么优点和缺点 523种经典设计模式的组织种经典设计模式的组织n按照两条准则对23种经典设计模式进行分类。n目的准则:模式用来完成什么工作l创建型:与对象的创建有关;l结构型:处理类或对象的组合;l行为型:对类或对象怎样交互和怎样分配职责进行描述。n范围准则:模式用于类还是对象l类模式(处理类和子类的编译时关系)l对象模式

2、(对象间运行时关系)类模式与对象模式类模式与对象模式n创建型n类模式:将对象的部分创建工作延迟到子类。类模式:将对象的部分创建工作延迟到子类。n对象模式:将对象的部分创建工作延迟到另一个对象中。对象模式:将对象的部分创建工作延迟到另一个对象中。n结构型n类模式:使用继承机制来组合类。类模式:使用继承机制来组合类。n对象模式:描述了对象的组装方式。对象模式:描述了对象的组装方式。n行为型n类模式:使用继承描述算法和控制流。类模式:使用继承描述算法和控制流。n对象模式:描述一组对象怎样协作完成单个对象所无法完对象模式:描述一组对象怎样协作完成单个对象所无法完成的任务。成的任务。6创建型模式的主要作

3、用创建型模式的主要作用7-8-经典设计模式:经典设计模式:GoFFactory MethodAdapter_ClassInterpreterTemplate MethodAbstract FactoryBuilderPrototypeSingletonAdapter_ObjectBridgeCompositeDecoratorFacadeFlyweightProxyChain of ResponsibilityCommandIteratorMediatorMementoObserverStateStrategyVisitor怎么选择设计模式怎么选择设计模式-9-下面的方法有助于发现针对特定问题

4、的设计模式下面的方法有助于发现针对特定问题的设计模式考虑设计模式是怎样解决设计问题考虑设计模式是怎样解决设计问题浏览模式的意图部分浏览模式的意图部分研究模式怎样互相关联研究模式怎样互相关联 研究目的相似的模式研究目的相似的模式 检查重新设计的原因检查重新设计的原因 考虑设计中哪些是可变的考虑设计中哪些是可变的 1023种经典设计模式种经典设计模式序号序号模式名称模式名称意图意图1Abstract Factory提供一个创建一系列相关或相互依赖对象提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。的接口,而无需指定它们具体的类。2Adapter将一个类的接口转换成客户希望的另外

5、一将一个类的接口转换成客户希望的另外一个接口。个接口。Adapter模式使得原本由于接口模式使得原本由于接口不兼容而不能一起工作的那些类可以一起不兼容而不能一起工作的那些类可以一起工作。工作。3Bridge将抽象部分与它的实现部分分离,使它们将抽象部分与它的实现部分分离,使它们都可以独立地变化。都可以独立地变化。4Builder将一个复杂对象的构建与它的表示相分离,将一个复杂对象的构建与它的表示相分离,使得同样的构建过程可以创建不同的表示。使得同样的构建过程可以创建不同的表示。11序号序号模式名称模式名称意图意图5Chain of Responsibility为解除请求的发送者和接收者之间耦合

6、,为解除请求的发送者和接收者之间耦合,而使多个对象都有机会处理这个请求。而使多个对象都有机会处理这个请求。将这些对象连成一条链,并沿着这条链将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它。传递该请求,直到有一个对象处理它。6Command将一个请求封装为一个对象,从而使你将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化;对可用不同的请求对客户进行参数化;对请求排队或记录请求日志,以及支持可请求排队或记录请求日志,以及支持可取消的操作。取消的操作。 23种经典设计模式种经典设计模式1223种经典设计模式种经典设计模式序号序号模式名称模式名称意图意图7 7Com

7、positeComposite将对象组合成树形结构以表示将对象组合成树形结构以表示“部分部分- -整体整体”的层次结构。它使得客户对单个的层次结构。它使得客户对单个对象和复合对象的使用具有一致性。对象和复合对象的使用具有一致性。8 8DecoratorDecorator动态地给一个对象添加一些额外的职责。动态地给一个对象添加一些额外的职责。就扩展功能而言,就扩展功能而言, 它比生成子类方式它比生成子类方式更为灵活。更为灵活。9 9FacadeFacadeFacadeFacade模式定义了一个高层接口,这个模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。接口使得这一子系统更加容易使用

8、。1323种经典设计模式种经典设计模式序号序号模式名称模式名称意图意图10Factory Method定义一个用于创建对象的接口,让子类决定定义一个用于创建对象的接口,让子类决定将哪一个类实例化。将哪一个类实例化。Factory Method使一个使一个类的实例化延迟到其子类。类的实例化延迟到其子类。11Flyweight运用共享技术有效支持大量细粒度的对象。运用共享技术有效支持大量细粒度的对象。12Interpreter给定一个语言给定一个语言, 定义它的文法的一种表示,定义它的文法的一种表示,并定义一个解释器并定义一个解释器, 该解释器使用该表示来该解释器使用该表示来解释语言中的句子。解释

9、语言中的句子。 13Iterator提供一种顺序访问一个聚合对象中各个元素提供一种顺序访问一个聚合对象中各个元素的的方法方法, 不需暴露该对象的内部表示不需暴露该对象的内部表示。1423种经典设计模式种经典设计模式序号序号模式名称模式名称意图意图1414MediatorMediator用一个中介对象来封装一系列的对象交互。用一个中介对象来封装一系列的对象交互。中介者使各对象不需要显式地相互引用,中介者使各对象不需要显式地相互引用,从而使其耦合松散,而且可以独立地改变从而使其耦合松散,而且可以独立地改变它们之间的交互。它们之间的交互。1515MementoMemento在不破坏封装性的前提下,捕

10、获一个对象在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状的内部状态,并在该对象之外保存这个状态。这样以后就可将该对象恢复到保存的态。这样以后就可将该对象恢复到保存的状态。状态。1616ObserverObserver定义对象间的一种一对多的依赖关系定义对象间的一种一对多的依赖关系,以,以便当一个对象的状态发生改变时便当一个对象的状态发生改变时, ,所有依赖所有依赖于它的对象都得到通知并自动刷新于它的对象都得到通知并自动刷新。15序号序号模式名称模式名称意图意图17Prototype用原型实例指定创建对象的种类,并且通用原型实例指定创建对象的种类,并且通过拷贝这个原型来

11、创建新的对象。过拷贝这个原型来创建新的对象。18Proxy为其他对象提供一个代理以控制对这个对为其他对象提供一个代理以控制对这个对象的访问。象的访问。19Singleton保证一个类仅有一个实例,并提供一个访保证一个类仅有一个实例,并提供一个访问它的全局访问点。问它的全局访问点。20State允许一个对象在其内部状态改变时改变它允许一个对象在其内部状态改变时改变它的行为的行为。对象看起来似乎修改了它所属的对象看起来似乎修改了它所属的类类。23种经典设计模式种经典设计模式16序号序号模式名称模式名称意图意图2121StrategyStrategy定义一系列的算法定义一系列的算法, ,把它们一个个

12、封装起来把它们一个个封装起来, , 并且使它们可相互替换。本模式使得算法的并且使它们可相互替换。本模式使得算法的变化可独立于使用它的客户。变化可独立于使用它的客户。2222Template Template MethodMethod定义一个操作中的算法的骨架,而将一些步定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。骤延迟到子类中。Template MethodTemplate Method使得子使得子类可以不改变一个算法的结构即可重定义该类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。算法的某些特定步骤。 2323VisitorVisitor表示一个作用于某对象结构中的各元素

13、的操表示一个作用于某对象结构中的各元素的操作。它使你可以在不改变各元素的类的前提作。它使你可以在不改变各元素的类的前提下定义作用于这些元素的新操作。下定义作用于这些元素的新操作。23种经典设计模式种经典设计模式u 在面向对象编程中, 常用的方法是用new操作符构造对象实例,但在有些情况下, new操作符直接生成对象会带来一些问题(1)创建对象之前必须清楚所要创建对象的类信息,但个别情况下无法达到此要求,譬如打开一个视频文件需要一个播放器对象,但是用户可能不知道具体播放器叫什么名字,需要系统分派给这个视频文件一个合适的播放器,这种情况下用new运算符并不合适。1、工厂模式、工厂模式工厂模式的由来

14、工厂模式的由来许多类型对象的创造需要一系列步骤许多类型对象的创造需要一系列步骤需要计算或取得对象的初始设置需要计算或取得对象的初始设置需要选择生成哪个子对象实例需要选择生成哪个子对象实例在生成需要对象之前必须先生成一些辅助功在生成需要对象之前必须先生成一些辅助功能对象能对象在这些情况在这些情况, , 新对象的建立就是一个新对象的建立就是一个 “过程过程”,而不仅仅是一个操作。为了能方便地完成这些复而不仅仅是一个操作。为了能方便地完成这些复杂的对象创建工作,可引入工厂模式。杂的对象创建工作,可引入工厂模式。 19工厂方法模式工厂方法模式n意图:定义一个用户创建对象的接口,让子类决定实例化哪一个类

15、。Factory Method使一个类的实例化延迟到其子类。n问题n有多个记录日志的类(如有多个记录日志的类(如FileLog和DBLog),对它们进行抽象,形成其抽象父类Logn客户必须通过它们的子类来记录日志(记录到文件或数据库)20工厂方法模式实例工厂方法模式实例n如果客户负责具体子类(FileLog或DBLog)对象的创建和使用,使得客户代码直接依赖于具体子类,而导致可扩展性降低。例如需要增加一个EventLog类(它将日志放在windows的事件记录中)。21工厂方法模式实例工厂方法模式实例n解决方法Copyright Fujian Normal University22工厂方法模式

16、工厂方法模式n工厂方法模式的结构23工厂方法模式工厂方法模式n工厂方法模式的参与者及其职责nProduct:定义工厂方法所创建的对象的接口nConcreteProduct:实现Product接口nCreatorl声明返回Product类型对象的工厂方法l可定义工厂方法的缺省实现(返回缺省的ConcreteProduct对象)l可调用工厂方法创建一个Product对象nConcreteCreator:重新定义工厂方法以返回一个ConcerteProduct对象。24工厂方法模式工厂方法模式n工厂方法模式的协作nCreator依赖于其子类来定义工厂方法n通过子类的工厂方法返回合适的Concrete

17、Product实例Copyright Fujian Normal University25工厂方法模式工厂方法模式n效果n为子类提供挂钩:用工厂方法在一个类的内部创建对象一般较直接创建对象更为灵活。n连接平行的类层次:具体的工厂类与具体的产品类往往具有平行的等级结构,它们之间一一对应。 一个日志管理器:设计日志记录类,支持记录的方法有FileLogEventLog工厂模式实例分析工厂模式实例分析/ LogFactory类public abstract class LogFactory public abstract Log Create();工厂模式实例分析工厂模式实例分析/ FileFact

18、ory类 public class FileFactory:LogFactory public override FileLog Create() return new FileLog(); / EventFactory类 public class EventFactory:LogFactory public override EventLog Create() return new EventLog(); public class App public static void Main(string args) LogFactory factory = new EventFactory();

19、 /FileFactory factory = new FileFactory(); Log log = factory.Create(); log.Write(); 工厂模式客户端程序工厂模式客户端程序u 客户程序有效避免了具体产品对象和应用程序之间的耦合,增加了具体工厂对象和应用程序之间的耦合u 在类内部创建对象通常比直接创建对象更灵活u 工厂模式通过面向对象的手法,将具体对象的创建工作延迟到子类,提供了一种扩展策略,较好的解决了紧耦合问题工厂模式实例分析工厂模式实例分析2、策略模式、策略模式Strategyn在实际中我们经常会发现一个问题有多种可选的策略,这些策略在概念上具有相同的功能,

20、但是适用于不同的环境n如果我们简单的使用继承关系来对这些策略上的差异进行建模,可能会导致很多问题:n类的个数迅速失控n代码大量重复、冗余n复用无法进行问题问题这是一个电子商务系统,其中有一个控制器对象(这是一个电子商务系统,其中有一个控制器对象(TaskControllerTaskController),用于处理销售请求。能够确认何时有人),用于处理销售请求。能够确认何时有人在请求销售订单,并将请求转给在请求销售订单,并将请求转给SalesOrderSalesOrder对象处理对象处理SalesOrderSalesOrder对象的功能包括:对象的功能包括:允许客户通过允许客户通过GUIGUI填

21、写订单填写订单处理税额的计算处理税额的计算处理订单,打印销售收据处理订单,打印销售收据问题问题n新的需求新的需求n要处理多种税额计算的方法。要处理多种税额计算的方法。例如要处理美国、加拿大、中国三个国家的税收方法(税例如要处理美国、加拿大、中国三个国家的税收方法(税法不同计税方法就不同)法不同计税方法就不同)n应对策略:应对策略:n复制粘贴修改复制粘贴修改n使用使用SwitchSwitch语句语句n使用继承使用继承前两种方法的问题不言而喻,我们肯定不会采用。前两种方法的问题不言而喻,我们肯定不会采用。看起来,继承是一种不错的方案,我们看看看起来,继承是一种不错的方案,我们看看问题问题TaskC

22、ontrollerTaskControllerSalesOrderSalesOrder+calcTax( )+calcTax( )CANSalesOrderCANSalesOrder+calcTax( )+calcTax( )CHNSalesOrderCHNSalesOrder+calcTax( )+calcTax( )USASalesOrderUSASalesOrder+calcTax( )+calcTax( )看起来不错,但是当变化继续发生的时候。看起来不错,但是当变化继续发生的时候。问题问题n现在又出现了新的变化,希望在打印收据时有大单(现在又出现了新的变化,希望在打印收据时有大单(A4

23、A4纸)、小单(纸)、小单(B5B5纸)和固定票据三种格式(在一个固定格式的空票据上打印)纸)和固定票据三种格式(在一个固定格式的空票据上打印)n为了应对上述需求,我们修改上述设计为了应对上述需求,我们修改上述设计TaskControllerTaskControllerSalesOrderSalesOrder+ +printOrderprintOrder( )( )+ +calcTaxcalcTax( )( )+GUI( )+GUI( )CANSalesOrderCANSalesOrder+printOrder( )+printOrder( )+calcTax( )+calcTax( )+GU

24、I( )+GUI( )CHNSalesOrderCHNSalesOrder+ +printOrderprintOrder( )( )+ +calcTaxcalcTax( )( )+GUI( )+GUI( )USASalesOrderUSASalesOrder+printOrder( )+printOrder( )+calcTax( )+calcTax( )+GUI( )+GUI( )n问题进一步恶化问题进一步恶化新的需求:要求能够支持两种不同的新的需求:要求能够支持两种不同的GUIGUI输入订单信输入订单信息,一种是息,一种是BrowserBrowser输入,一种是输入,一种是ClientCl

25、ient输入输入现在已经有现在已经有33218个类了个类了TaskControllerTaskControllerSalesOrderSalesOrder+ +printOrderprintOrder( )( )+ +calcTaxcalcTax( )( )+GUI( )+GUI( )CANSalesOrderCANSalesOrder+printOrder( )+printOrder( )+calcTax( )+calcTax( )+GUI( )+GUI( )CHNSalesOrderCHNSalesOrder+printOrder( )+printOrder( )+calcTax( )+c

26、alcTax( )+GUI( )+GUI( )USASalesOrderUSASalesOrder+printOrder( )+printOrder( )+calcTax( )+calcTax( )+GUI( )+GUI( )问题问题由此产生的问题:n类的个数迅速失控n代码大量重复、冗余n复用无法进行策略模式的由来策略模式的由来p 多种算法实现同一功能,客户希望在运行时根据上下文选择其中一个算法p 传统策略算法的缺点p 使用算法的类复杂而难于维护,尤其当需要支持多种算法且每种算法都很复杂时问题会更加严重p 不同的时候需要不同的算法,支持并不使用的算法可能带来性能的负担p 算法的实现和使用算法的

27、对象紧紧耦合在一起,使新增算法或修改算法变得十分困难,系统应对变化的能力很差p 将每种算法的实现都剥离出来构成一个个独立算法对象,再从这些对象中抽象出公共算法接口,最后将算法接口组合到使用算法类中策略模式的意图和适用性策略模式的意图和适用性p 意图:定义一系列算法,一个个进行封装,并使其可相互替换。策略模式使得算法可独立于使用它的客户而变化p 适用场合p 在软件构建过程中,某些对象使用的算法可能多种多样,经常改变,如果将这些算法都编码到对象中,将会使得对象变得异常复杂;而且有时候支持不同的算法也是一个性能负担p 如何在运行时根据需要透明地更改对象的算法?如何将算法与对象本身解耦,从而避免上述问

28、题?策略模式很好地解决了这两个问题策略模式的结构策略模式的结构策略模式的参与者策略模式的参与者p Strategyp 定义所有支持算法的公共接口p Context使用该接口调用某ConcreteStrategy定义的算法p ConcreteStrategyp 以Strategy接口实现某具体算法p Contextp 用一个ConcreteStrategy对象来配置p 维护一个对Strategy对象的引用p 可定义一个接口来让Strategy访问它的数据策略模式的效果分析策略模式的效果分析p 算法和使用算法的对象相互分离,客户程序可以在运行时动态选择算法,代码复用性好,便于修改和维护p 用组合替

29、代继承,效果更好。若从Context直接生成子类,也可以实现对象的多种算法,但继承使子类和父类紧密耦合,使Context类难以理解、难以维护和难以扩展。策略模式采用组合方式,使Context和Strategy之间的依赖很小,更利于代码复用p 消除了冗长的条件语句序列,将不同的算法硬编码进一个类中,选择不同的算法必然要使用冗长的条件语句序列,采用策略模式将算法封装在一个个独立的Strategy类中消除了这些条件语句策略模式的效果分析策略模式的效果分析p 算法的动态选择,Strategy模式可以提供相同行为的不同实现,客户可以根据不同的上下文从不同的策略中选择算法p 客户必须了解不同的Strate

30、gy,一个客户要选择一个合适的Strategy就必须知道这些Strategy到底有什么不同p Strategy和Context之间的通信开销加大,根据算法的需要,Context必须向每个不同的具体Strategy类实例传递不同的参数,因此Strategy接口就要传递所有这些不同参数的集合,导致Context会创建和传递一些永远用不到的参数p 增加了类和对象数目,因为各种算法被抽取出来单独成类,导致了对象数目增加,这种情况在算法较多时更加严重订单处理的例子订单处理的例子订单处理的例子订单处理的例子订单处理的例子的代码订单处理的例子的代码订单处理的例子的代码订单处理的例子的代码订单处理的例子的代码

31、订单处理的例子的代码class calcTaxpublic:double taxAmount (long itemSold, double price)=0;class canTax: public calcTaxpublic:double taxAmount (long itemSold, double price)return 0.0;class usTax : public calcTaxpublic:double taxAmount (long itemSold, double price)return 1.0;Strategy模式的关键特征模式的关键特征意图意图可以根据不同的语境灵活

32、的配置业务规则或算法可以根据不同的语境灵活的配置业务规则或算法问题问题对于某种算法的选择依赖于用户的请求内容或算法所对于某种算法的选择依赖于用户的请求内容或算法所使用的数据。如果某处的算法始终不会变化,则没有使用的数据。如果某处的算法始终不会变化,则没有必要使用必要使用StrategyStrategy模式模式解解将算法的实现和选择相分离。允许根据语境来选择算将算法的实现和选择相分离。允许根据语境来选择算法法参与者和参与者和协作者协作者 Strategy Strategy给出了应如何使用各种不同算法的信息给出了应如何使用各种不同算法的信息 ConcreteStrategies ConcreteS

33、trategies 实现了这些不同的算法实现了这些不同的算法 Context Context 通过一个通过一个StrategyStrategy类型的引用使用了特定类型的引用使用了特定类型的类型的ConcreteStrategy. StrategyConcreteStrategy. Strategy和和ContextContext通过通过交互实现选定的算法交互实现选定的算法( (有时有时StrategyStrategy必须查询必须查询Context.) Context.) ContextContext将将clientclient 的请求转发给的请求转发给Strategy.Strategy.效果效

34、果 Strategy Strategy定义了一族算法定义了一族算法 可以减少可以减少SwitchSwitch和条件分支语境(和条件分支语境(if,elseif,else) 所有的算法必须用同样的接口进行调用。所有的算法必须用同样的接口进行调用。实现实现由使用算法的类由使用算法的类ContextContext包含一个抽象类包含一个抽象类StrategyStrategy,StrategyStrategy类有一个抽象方法决定如何调用算法。类有一个抽象方法决定如何调用算法。 每一个每一个派生类实现一个需要的算法派生类实现一个需要的算法. . 注意:注意: 如果你想有一些缺省行为的话,决定如何调用算如果

35、你想有一些缺省行为的话,决定如何调用算法的方法不能为抽象方法。法的方法不能为抽象方法。 注意注意: : 在最初的在最初的StrategyStrategy模式中模式中, , 选择特定算法实现的选择特定算法实现的责任由责任由ClientClient对象根据对象根据ContextContext对象的信息完成对象的信息完成Strategy模式的关键特征模式的关键特征练习练习n一个贩卖各类书籍的电子商务网站的购物车(Shopping Cart)系统n计算本次购物金额的方法。比如:n对所有的教材类图书实行每本1元的折扣n对连环画类图书提供每本7的促销折扣n对非教材类的计算机图书有3的折扣n对其余的图书没有

36、折扣使用继承的方法使用继承的方法使用策略模式的方法使用策略模式的方法策略模式实例:负载监视器策略模式实例:负载监视器53n监视计算节点的负载状态(如CPU占用率)n以CPU占用率的监视为例,不同条件下(例如不同种类不同版本的OS)获得CPU占用率的方法不同n怎样在一个程序中实现对这些不同条件的适应呢?Switch-caseEnum MonitorType Win32, Win64, Ganglia;float getLoad(MonitorType type) switch (type) case Win32: /get system load via Win32 APIs return lo

37、ad; case Win64: /get system load via Win64 APIs return load; case Ganglia: /get system load via ganglia interface return load; ? ?使用继承使用继承n一种方案是使用继承针对接口编程代码示例代码示例class Monitor public: virtual float getLoad() = 0;class Win32Monitor : public Monitor public: float getLoad() / return load;class Win64Mon

38、itor : public Monitor public:float getLoad() / return load; ;void Test() Monitor * monitor = new Win32Monitor(); float load = monitor-getLoad(); cout load getLoad(); long getLatency(char *node) return m_getLatency - getLatency(node); void setGetLoadStrategy(GetLoadStrategy *getLoad) m_getLoad = getL

39、oad; void setLatencyStrategy(LatencyStrategy *getLatency) /;策略模式下的策略模式下的Monitor(3)void Test() GetLoadStrategy* getLoad = new Win32GetLoadStrategy (); LatencyStrategy* getLatency = new DirectLatencyStrategy(); Monitor * monitor = new Monitor(getLoad, getLatency); float load = monitor - getLoad(); lon

40、g latency = monitor - getLatency(); monitor - setLatencyStrategy(new ProxyLatencyStrategy(); long another_latency = monitor - getLatency(); 策略的选择策略的选择另外一个另外一个Strategy的例子的例子(1)n用“飞”和“游”两个“策略”来定义各种不同的动物n能飞的鸟n能游的鱼n即不能飞也不能游的n请自行分析这个例子另外一个另外一个Strategy的例子的例子(2)class FlyBehaviorpublic: virtual void fly() =

41、 0;class BirdFly : public FlyBehaviorpublic: void fly() cout “bird fly” endl; ;class CannotFly: public FlyBehaviorpublic: void fly() cout “can not fly” endl; ;另外一个另外一个Strategy的例子的例子(3)class SwimBehaviorpublic: virtual void swim() = 0;class FishSwim : public SwimBehaviorpublic: void swim() cout “fish

42、 swim” endl; ;class CannotSwim: public SwimBehaviorpublic: void swim() cout “can not swim” fly(); void swim() m_swim - swim();class Fish : public Animalpublic: void Fish() m_swim = new FishSwim(); m_fly = new CannotFly(); ;class Bird: public Anialpublic: void Bird() m_swim = new CannotSwim(); m_fly

43、= new BirdFly(); ;3、装饰(、装饰(Decorator)模式)模式p 动态给对象添加额外职责。比如:一幅画有没有画框都可以挂在墙上,画是被装饰者。在挂在墙上之前,画可以被蒙上玻璃,装到框子里,玻璃画框就是装饰p 不改变接口,但加入责任。Decorator提供了一种给类增加职责的方法,不是通过继承,而是通过组合实现的装饰(装饰(Decorator)模式的意图和适用性)模式的意图和适用性p 意图p 动态地给一个对象添加一些额外的职责。就增加功能来说,Decorator 模式比生成子类更为灵活p 适用场合p 在不影响其他对象的情况下,以动态、透明的方式给单个对象添加职责p 当不能采

44、用生成子类的方法进行扩充时。一种情况是,可能有大量独立扩展,每一种组合将产生大量的子类,使得子类数目呈爆炸性增长。另一种情况是因为类定义被隐藏,或类定义不能用于生成子类装饰(装饰(Decorator)模式的结构)模式的结构p Componentp 对象接口:可以给对象动态地添加职责p ConcreteComponentp 具体对象p Decoratorp 维持一个指向Component对象的指针,并定义一个与Component接口一致的接口p ConcreteDecoratorp 向组件添加职责p Decorator将请求转发给它的Component对象,并有可能在转发请求前后执行一些附加的动

45、作装饰(装饰(Decorator)模式的结构)模式的结构装饰(装饰(Decorator)模式的评价)模式的评价p 使用Decorator模式可以很容易地向对象添加职责。可以用添加和分离的方法,在运行时添加和删除职责p 使用Decorator模式可以很容易地重复添加一个特性,而两次继承则极容易出错p 避免在层次结构高层的类有太多的特征:可以从简单的部件组合出复杂的功能。具有低依赖性和低复杂性p 缺点:Decorator与Component不一样,使用装饰时不应该依赖对象标识;有许多小对象Decorator模式解决的问题模式解决的问题n我们已经有了一些基本功能,可以通过继承在此基础上对已有功能进行

46、扩展。例如:n已经有了汽车具有:行驶、转向、停止等基本功能n扩展豪华房车除了基本功能外,增加:开闭天窗、卫星定位、车窗防弹、车载冰箱等功能n扩展超炫跑车除了基本功能外,增加:开闭顶棚、8档变速、涡轮加速、自动驾驶等功能。继承可以方便的实现上述扩展Decorator模式解决的问题模式解决的问题n但是,对于超豪华、定制的名车怎么办?n要量身定做汽车,上面的功能希望能够自由选择:n开闭天窗、卫星定位、车窗防弹、车载冰箱n开闭顶棚、8档变速、涡轮加速、自动驾驶比如一辆既有豪华房车般奢华,同时又能如超炫跑车般享受驾驶乐趣的车:n卫星定位、车载冰箱、 8档变速、自动驾驶n开闭天窗、卫星定位、车窗防弹、 8

47、档变速、涡轮加速、自动驾驶n开闭天窗、车载冰箱、涡轮加速、自动驾驶用继承的方式无法应对上面的变化性,因为订做的情况下,可能的组合有太多种了。Decorator模式解决的问题模式解决的问题n对上述问题的总结:我们如何应对给一个对象,而不是整个类添加功能毕竟,定制的轿车不需要量产,也就是说,我们不需要为每一款定制的靓车编写一个类,并期望用这个类派生多个实例Decorator模式模式示例示例1:n假设有一个对象TextView,可以在窗口中显示正文nTextView没有滚动条(缺省)但是有时候需要nTextView没有粗黑边框(缺省)有时候也需要n抽象的说:有一个基本功能,还有些可选功能,每一个具体

48、的对象,在基本功能的基础上通过选用不同的可选功能来定制完美的Decorator模式应用场景n基本功能作为:ConcreteComponentn可选功能作为:ConcreteDecortator解决方法解决方法代码代码class VisualComponentpublic:VisualCompont( );virtual void Draw( );virtual void Resize( );/.;class Decorator:public VisualComponentpublic:Decorator(VisualComponent*);virtual void Draw( )_compon

49、ent-Draw( );virtual void Resize( )_component-Resize( );/.private:VisualComponent* _component;代码代码class BorderDecorator:public Decoratorpublic:BorderDecorator(VisualComponent* p, int borderWidth):Decorator(p)_width=borderWidth;virtual void Draw( )Decorator:Draw();DrawBorder(_width);private:void DrawB

50、order(int);int _width;class ScrollDecorator:public Decorator/与与BorderDecorator类似类似;n假设有一个Window类,其中有一个方法SetContents是VisualComponent的Clientvoid Window:SetContents(VisualComponent* contents)/.n对于各种情况下的TextViewWindow* win=new Window;TextView* tv=new TextView;n最简单的 window-SetContents(tv);n有边框的 window-Se

51、tContents(new BorderDecortator(tv,1);n有滚动条的 window-SetContents(new ScrollDecortator(tv);n既有边框又有滚动条的window-SetContents(new BorderDecortator(new ScrollDecorator(tv),1);Decorator模式的关键特征模式的关键特征意图意图动态的为一个对象添加职责动态的为一个对象添加职责问题问题要使用的对象将执行所需的基本功能。但是,在这些要使用的对象将执行所需的基本功能。但是,在这些基本功能确定以后,可能需要为这个对象添加一些其基本功能确定以后,可

52、能需要为这个对象添加一些其他附加功能,并且对于不同的情况可能添加附加功能他附加功能,并且对于不同的情况可能添加附加功能的种类和数量都是不确定的。的种类和数量都是不确定的。解解通过添加装饰类,而不是扩展子类,在运行时为基本通过添加装饰类,而不是扩展子类,在运行时为基本类对象扩充功能。类对象扩充功能。参与者和参与者和协作者协作者 ConcreteComponentConcreteComponent让让DecoratorDecorator对象为自己添加功对象为自己添加功能。有时候用能。有时候用ConcreteComponentConcreteComponent的派生类提供核心功的派生类提供核心功能,

53、在这种情况下能,在这种情况下ConcreteComponentConcreteComponent不再是具体的,不再是具体的,而是抽象的。而是抽象的。ComponentComponent类定义了所有这些类的接口。类定义了所有这些类的接口。Decorator模式的关键特征模式的关键特征效果效果所添加的功能放在小对象中。好处是可以在所添加的功能放在小对象中。好处是可以在ConcreteComponentConcreteComponent对象的功能之前或之后动态添加功能。对象的功能之前或之后动态添加功能。注意,虽然装饰对象可以在被装饰对象之前或之后添加功能,注意,虽然装饰对象可以在被装饰对象之前或之后

54、添加功能,但是对象链总是终于但是对象链总是终于ConcreteComponentConcreteComponent对象对象实现实现创建一个抽象类来表示原类和要添加到这个类的新功能。在创建一个抽象类来表示原类和要添加到这个类的新功能。在装饰类中,将对新功能的调用放在对紧随其后对象的调用之装饰类中,将对新功能的调用放在对紧随其后对象的调用之前或之后,以获得正确的顺序。前或之后,以获得正确的顺序。练习练习n有一个程序打印发票,所有发票都需要有正文 部分,同时根据用户需要有的订单需要有表头,有的需要有页脚。表头有3种,分别叫做“表头1”、 “表头2”、 “表头3”;页脚有2种,分别叫做“页脚1”、“页

55、脚2”。不同的用户可能要求有表头,没有表头;有1种表头,或者同时有2个表头,或者3个表头;有页脚,没有页脚;有1个页脚,或者2个不同的页脚。解答解答4、组合(、组合(Composite)模式)模式p 表达部分与整体的树形结构机箱计算机显示器键盘鼠标主板CPU硬盘电源显卡网卡组合(组合(Composite)模式的由来)模式的由来p 抽象p 单一对象(Leaf):键盘、鼠标、显示器、硬盘、电源、 CPU、显卡、网卡p 组合对象(Composite):计算机、机箱、主板p 部件(Component):单一对象与组合对象的统称p 组合对象既可以包括单一对象,也可以包括组合对象组合(组合(Composi

56、te)模式的意图和适用性)模式的意图和适用性p 意图:p 将对象组合成树形结构,表示“部分/整体”层次结构p 使用户对单一对象和组合对象使用具有一致性接口p 适用性p 表示对象的部分-整体层次结构p 忽略总体对象与单一对象差异,统一使用组合结构的所有对象组合(组合(Composite)模式的结构)模式的结构组合(组合(Composite)模式的参与者)模式的参与者组合(组合(Composite)模式的参与者)模式的参与者p Componentp 为组合对象声明接口p 声明一个接口用于访问和管理Component的子组件p Leafp 表示叶节点对象,没有子节点p 定义图元对象的行为p Comp

57、ositep 定义复合部件的行为p 存储子部件p Clientp 通过Component接口操纵组合部件的对象组合(组合(Composite)模式的效果)模式的效果p 定义了包含基本对象和组合对象的类层次结构p 简化客户代码,一致使用组合对象和单个对象p 容易增加新类型的组件p 用户使用Component类接口与组合结构中的对象进行交互。如果接收者是叶节点,直接处理请求;如果接收者是Composite,将请求发送给它的子部件,在转发请求之前和/或之后可能执行一些辅助操作组合(组合(Composite)模式的实现)模式的实现p 显式的父对象的引用,在子对象中给出父对象的引用,可以很容易地遍历所有

58、父对象p 最大化Component接口p 声明管理子部件的操作p 组件的存储(什么样的数据结构?)94迭代子模式迭代子模式(Iterator)模式)模式p将对象职责分离,最大限度减少彼此之间的耦合程度,从而建立一个松散耦合的对象网络p集合对象拥有两个职责:一是存储内部数据;二是遍历内部数据。从依赖性看,前者为对象的根本属性,而后者既是可变化的,又是可分离的。可将遍历行为分离出来,抽象为一个迭代器,专门提供遍历集合内部数据对象行为。这是迭代子模式的本质95迭代子模式的意图和适用性迭代子模式的意图和适用性p意图p迭代子模式的目的是设计一个迭代器,提供一种可顺序访问聚合对象中各个元素的方法,但不暴露

59、该对象内部表示p适用场合p访问一个聚合对象的内容而无需暴露其内部表示p支持对聚合对象的多种遍历p为遍历不同的聚合结构提供一个统一接口 (支持多态迭代)96迭代子模式的结构迭代子模式的结构97迭代子模式的参与者迭代子模式的参与者pIteratorp定义访问和遍历元素的接口pConcrete Iteratorp实现迭代器接口pAggregatep定义创建迭代器对象的接口pConcrete Aggregatep实现创建迭代器的接口,返回具体迭代器的一个实例98迭代子模式的效果分析迭代子模式的效果分析p简化了聚集的行为,迭代子具备遍历接口,聚集不必具备遍历接口p每一个聚集对象都可以有一个或者更多的迭代

60、子对象,每一个迭代子的迭代状态可以彼此独立p遍历算法被封装到迭代子对象中,迭代算法可以独立于聚集对象变化。客户端不必知道聚集对象的类型,通过迭代子就可以读取和遍历聚集对象。聚集内部数据发生变化不影响客户端程序6、模板方法(、模板方法(Template Method)模式)模式n两类问题n问题1:复用问题我们经常会面临许多框架结构上相似,但是却在细节上稍有不同的代码n例如:一个电子商务应用软件中,经常需要查询数据库,处理数据库中的数据。这个软件需要支持两种不同类型的DBMSOracle和MS SQL Server。两个不同的DBMS虽然都支持SQL语句,但是其语句在语法上却略有不同。访问两个不同

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论