《5设计模式.ppt》由会员分享,可在线阅读,更多相关《5设计模式.ppt(78页珍藏版)》请在taowenge.com淘文阁网|工程机械CAD图纸|机械工程制图|CAD装配图下载|SolidWorks_CaTia_CAD_UG_PROE_设计图分享下载上搜索。
1、什么是设计模式什么是设计模式1设计模式 “设计模式(pattern)是从许多优秀的软件系统中总结出的成功的可复用的设计方案”。2GOF之说 “尽管Alexander所指的是城市和建筑设计模式,但他的思想也同样适用于面向对象设计模式,只是在面向对象的解决方案里,我们用对象和接口代替了墙壁和门窗。两类模式的核心都在于提供了相关问题的解决方案”。记录模式的四个基本要素记录一个设计模式需有四个基本要素:1名称名称:一个模式的名称高度概括该模式的本质,有利于该行业统一术语、便于交流使用。2问题:问题:描述应该在何时使用模式,解释设计问题和问题存在的前因后果,描述在怎样的环境下使用该模式。3方案方案:描述
2、设计的组成部分,它们之间的相互关系及各自的职责和协作方式。4效果效果:描述模式的应用效果及使用模式应当权衡的问题。主要效果包括使用模式对系统的灵活性、扩充性和复用性的影响。l例如,GOF之书如下记录中介者模式:l名称名称:中介者l问题:问题:用一个中介者来封装一系列的对象交互。中介者使各对象不需要显示地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互。l方案:方案:中介者(Mediator)接口、具体中介者(ConcreteMediator)、同事(Colleague)、具体同事(ConcreteColleague)。l效果效果:减少了子类的生成、将各个同事解耦、简化了对象协议、控
3、制集中化。设计模式的起源设计模式的起源1软件领域的设计模式起源主要是受到1977年建筑大师Alexander出版的A Pattern Language:Towns,Building,Construction一书。2Alexander在其著作中将其建筑行业中的许多问题的最佳解决方案记录为200多种模式,其思想不仅在建筑行业影响深远,而且很快影响到了软件设计领域。31987年,Kent Beck和Ward Cunningham将Alexander在建筑学上的模式观点应用于软件设计,开发了一系列模式,并用Smalltalk语言实现了雅致的用户界面。Kent Beck和Ward Cunningham在
4、1987年举行的一次面向对象的会议上发表了论文:在面向对象编程中使用模式,该论文发表后,有关软件的设计模式论文以及著作相继出版。GOF之著作之著作1目前,被公认在设计模式领域最具影响力的著作是Erich Gamma、Richard Helm、Ralph Johnson和John Vlissides在1994年合作出版的著作:Design Patterns:Elements of Reusable Object-Oriented Software(中译本设计模式:可复用的面向对象软件的基本原理。2该书的四位作者在其著作中记录了他们在四年多的工作中所发现的23个模式。3设计模式一书被广大喜爱者昵称
5、为GOF(Gang of Four)之书(四人帮之书),被认为是学习设计模式的必读著作。4GOF之书已经被公认为是设计模式领域的奠基之作。学习设计模式的重要性学习设计模式的重要性1一个好的设计系统往往是易维护、易扩展、易复用的。2有经验的设计人员或团队知道如何使用面向对象语言编写出易维护、易扩展和易复用的程序代码。3设计模式一书正是从这些优秀的设计系统中总结出的设计精髓。4学习设计模式对提高设计能力无疑是非常有帮助的,尽管GOF之书并没有收集全部的模式,但所阐述的23种模式无疑是使用频率最高的模式。5设计模式的目的不是针对软件设计和开发中的每个问题都给出解决方案,而是针对某种特定环境中通常都会
6、遇到的某种软件开发问题给出的可重用的一些解决方案。6学习设计模式不仅可以使我们使用好这些成功的模式,更重要的是可以使我们更加深刻地理解面向对象的设计思想,非常有利于我们更好地使用面向对象语言解决设计中的问题。7学习设计模式对于进一步学习、理解和掌握框架是非常有帮助的,比如Java EE中就大量使用了设计模式一书中的模式,对于熟悉设计模式的开发人员,很容易理解这些框架的结构,继而很好地使用框架来设计他们的系统。8设计模式一书所总结的成功模式不仅适合于面向对象语言,其思想及解决问题的方式也适合于任何和设计相关的行业,因此学习掌握设计模式无疑是非常有益的。合理使用模式合理使用模式 不是软件的任何部分
7、都需要套用模式来设计的,必须针对具体问题合理的使用模式。1.正确使用正确使用 当你设计某个系统,并确认所遇到的问题刚好适合使用某个模式,就可以考虑使用该模式到你的系统设计中,毕竟该模式已经被公认是解决该问题的成功方案,能使设计的系统易维护、可扩展性强、复用性好,而且这些经典的模式也容易让其他开发人员了解你的系统和设计思想。2.避免教条避免教条模式不是数学公式、也不是物理定律、更不是软件设计中的“法律”条文,一个模式只是成功解决某个特定问题的设计方案,你完全可以修改模式中的部分结构以符合你的设计要求。3.模式挖掘模式挖掘 模式不是用理论推导出来的,而是从真实世界的软件系统中被发现、按着一定规范总
8、结出来的可以被复用的方案。许多文献或书籍里阐述的众多模式实际上都是GOF书中经典模式的变形,这些变形模式都经过所谓的“三次规则”,即该模式已经在真实世界的三个方案中被成功的采用。可以从某个系统中洞察出某种新模式,只要经过“三次规则”就会被行业认可。4.避免乱用避免乱用 不是所有的设计中都需要使用模式,因为模式是总结出来的,事实上,真实世界中的许多设计实例都没有使用过GOF之书中的经典模式。在进行设计时,尽可能用最简单的方式满足系统的要求,而不是费尽心机地琢磨如何在这个问题中使用模式,一个设计中,可能并不需要使用模式就可以很好地满足系统的要求,如果牵强地使用某个模式可能会在系统中增加许多额外的类
9、和对象,影响系统的性能,因为大部分设计模式往往会在系统中加入更多的层,这不但增加复杂性,而且系统的效率也会下降。l5.了解反模式了解反模式l 所谓反模式就是从某些软件系统中总结出的不好的设计方案,反模式就是告诉你如何采用一个不好的方案解决一个问题。既然是一个不好的方案,为何还有可能被重复使用呢?这是因为,这些不好的方案表面上往往有很强的吸引力,人们很难一眼就发现它的弊端,因此,发现一个反模式也是非常有意义的工作。在有了一定的设计模式的基础之后,你可以用搜索引擎查找有关反模式的信息,这对于学习好设计模式也是非常有帮助的。开开-闭原则闭原则 所谓“开-闭原则”(Open-Closed Princi
10、ple)就是让你的设计应当对扩展开放,对修改关闭。怎么理解对扩展开放,对修改关闭呢?实际上这句话的本质是指当一个设计中增加新的模块时,不需要修改现有的模块。我们在给出一个设计时,应当首先考虑到用户需求的变化,将应对用户变化的部分设计为对扩展开放,而设计的核心部分是经过精心考虑之后确定下来的基本结构,这部分应当是对修改关闭的,即不能因为用户的需求变化而再发生变化,因为这部分不是用来应对需求变化的。如果您的设计遵守了“开-闭原则”,那么这个设计一定是易维护的,因为在设计中增加新的模块时,不必去修改设计中的核心模块。比如,我们在2.1节给出的设计中有4个类,类图如下:该设计中的Geometry和Pi
11、llar类就是系统中对修改关闭的部分,而Geometry的子类是对扩展开放的部分。当我们向系统再增加任何Geometry的子类时(对扩展开放),不必修改Pillar类,就可以使用Pillar创建出具有Geometry的新子类指定的底的柱体。通常我们无法让设计的每个部分都遵守“开-闭原则”,对设计中最有可能因需求变化而需要改变的地方,然后想办法应用“开-闭原则”。当设计某些系统时,我们经常需要面向抽象来考虑系统的总体设计,不要考虑具体类,这样就容易设计出满足“开-闭原则”的系统,在程序设计好后,首先对abstract类的修改关闭,否则,一旦修改abstract类,比如,为它再增加一个abstra
12、ct方法,那么abstract类所有的子类都需要做出修改;应当对增加abstract类的子类开放,即在程序中再增加子类时,不需要修改其它面向抽象类而设计的重要类。多用组合少用继承原则 之所以提倡多用组合,少用继承,是因为在许多设计中,人们希望系统的类之间尽量是低耦合的关系,而不希望是强偶合关系。即在许多情况下需要避开继承的缺点,而需要组合的优点。怎样合理地使用组合,而不是使用继承来获得方法的复用需要经过一定时间的认真思考、学习和编程实践才能悟出其中的道理,这也是促使我们学习设计模式的原因之一。关于多用组合,少用继承,在后面的设计模式中,比如第6章的装饰模式,第7章的策略模式以及第12章的中介者
13、模式中都有体现。高内聚高内聚-低耦合原则低耦合原则 如果类中的方法是一组相关的行为,则称该类是高内聚的,反之称为低内聚的。高内聚便于类的维护,而低内聚不利于类的维护,学习后面第11章迭代器模式时,会更深刻体会到这一原则。所谓低耦合就是尽量不要让一个类含有太多的其它类的实例的引用,以避免修改系统的其中一部分会影响到其它部分,比如在后面学习中介者模式时,就会体会到这一原则。设计目标和实现目标的方法l重用性,灵活性,可维护性重用性,灵活性,可维护性o重用灵活的设计重用灵活的设计o使代码处于通用层上使代码处于通用层上o最小化与其他类的相关性最小化与其他类的相关性l 健壮性健壮性 o重用可靠的设计重用可
14、靠的设计o重用健壮的部分重用健壮的部分q 有效性有效性/正确性正确性o模块化设计模块化设计o重用可信任的部分重用可信任的部分KitchenViewer Interface壁柜壁柜台面台面立柜立柜现代现代古典古典古希腊古希腊艺术艺术menudisplay areastyles举例:厨房视图 ModernClassicAntiqueArts&Crafts壁柜立柜台面Selecting Antique Style ModernClassicAntiqueArts&CraftsKitchenViewer Without Design PatternsKitchenClientrenderKitchen
15、()FloorCabinet ModernWallCabinetModernFloorCabinetAntiqueFloorCabinetAntiqueWallCabinetWallCabinet 设计目标:灵活性 我们的设计应该足够灵活地产生任何一个厨我们的设计应该足够灵活地产生任何一个厨房风格房风格AntiqueKStylegetWallCabinet()getFloorCabinet()抽象工厂思想KitchenStylegetWallCabinet()getFloorCabinet()ModernKStylegetWallCabinet()getFloorCabinet()WallCa
16、binet FloorCabinet AntiqueWallCabinetAntiqueFloorCabinetFloorCabinet getFloorCabinet()return new AntiqueFloorCabinet();FloorCabinet getFloorCabinet()return new ModernFloorCabinet();抽象工厂模式应用于厨房查看器KitchenStylegetWallCabinet()getFloorCabinet()KitchengetWallCabinet()getFloorcabinet()ClientrenderKitchen(
17、KitchenStyle)ModernKStylegetWallCabinet()getFloorCabinet()AntiqueKStylegetWallCabinet()getFloorCabinet()WallCabinet FloorCabinet ModernWallCabinetModernFloorCabinetAntiqueWallCabinetAntiqueFloorCabinet抽象工厂 设计模式StylegetComponentA()getComponentB()ClientdoOperation(Style myStyle)Style1getComponentA()ge
18、tComponentB()Style2getComponentA()getComponentB()ComponentA ComponentBStyle1ComponentAStyle1ComponentBStyle2ComponentAStyle2ComponentBCollection抽象工厂设计模式的变化StylegetComponentA()getComponentB()ClientdoOperation()Style1getComponentA()getComponentB()Style2getComponentA()getComponentB()ComponentA Componen
19、tBStyle1ComponentAStyle1ComponentBStyle2ComponentAStyle2ComponentBCollection getComponentA()getComponentB()关键概念:设计模式 类类的的组组合和算法完成了公共的合和算法完成了公共的设计设计目目标标 设计设计模式是一种模式是一种类类的的联联合体以及与之相伴的合体以及与之相伴的算法,算法,这这些算法能些算法能够实现够实现共同的共同的设计设计目目标标。按类型总结设计模式l创建型设计模式:以灵活的方式创建对象集合,用于管理对象的创建l结构型设计模式:代表相关对象的集合,用于将已有的代码集成到新的面
20、向对象设计中l行为型设计模式:在对象集合中捕获行为,用于封装行为的变化创建型设计模式l含义:含义:u以灵活或者约束的方式创建对象以灵活或者约束的方式创建对象l应用范围:应用范围:u设计包含对象集的应用程序,允许从单一的代码块中创建几个可能设计包含对象集的应用程序,允许从单一的代码块中创建几个可能的集合的集合l条件:必须俱备如下属性条件:必须俱备如下属性l在运行时可以创建集合的多个版本在运行时可以创建集合的多个版本l约束创建的对象:例如:确保只有一个实例约束创建的对象:例如:确保只有一个实例 创建型设计模式名字所能满足的设计目标所能满足的目标的应用实例设计模式的总结Factory设计模式在运行时
21、以灵活的方法创建对象,这些对象 是构造方法不能单独提供的从一个单一的控制代码版本,产生适合各种顾客的通用邮件信息通过使用返回对象的方法来创建 希望的对象Abstract Factory设计模式在运行时,从风格集合中作出选择,以创建协同的对象族显示厨房布局,允许用户在运行时选择一种风格捕获类的每个族,这个类的方法返回那种风格的对象ProtoType设计模式创建一个聚合对象,在这上聚合对象中选择的部分实质上是原型的复制显示厨房布局,允许用户在运行时选择一种壁柜类型,或者一种立柜类型等通过对原型进行的复制,产生 这种类型的对象Singleton(单态)设计模式确保一个类只有一个确切的实例,在整个应用
22、程序中都是可访问的建立一个应用程序来估计一个实验结果的值。在运行时,保证有一个确切的实验对象,并且能够被应用程序中的任何一个方法访问使构造方法私有化,从一个公有的静态方法中返回一个惟一的对象结构型设计模式含义:使用统一处理接口来表示诸如树含义:使用统一处理接口来表示诸如树这样的数据结构这样的数据结构应用范围:设计计以链表或树的形式来应用范围:设计计以链表或树的形式来安排对象的集合安排对象的集合结构型设计模式名字所能满足的设计目标所能满足的目标的应用实例设计模式的总结Composite(复合)静态目的:描述对象树;动态目的:允许用户代码能够访问任何节点下子树的单值函数;允许运行时树结构的变化描绘
23、一个公司的组织图。允许用户代码在雇员对象上调用printOrganization()方法,打印雇员的名字和所有附属资料。在运行时允许增加和删除雇员让组合类聚合其他组合类Decorator(装饰者)设计模式静态目的:描述对象列表;动态目的:允许用户代码使用分布在列表中的函数允许在线服装店的顾客能够看到自己穿着各种衣服的形象使用聚合连接对象Adapter(适配器)设计模式允许应用程序使用外部函数从头设计一个借贷应用程序,允许使用任何售货商类,这些类计算月付款数额引入一个协调者类边接应用程序以及具有我们所希望的功能的类Facade设计模式管理包含大量类的软件体系结构设计一个学生贷款程序的体系结构,一
24、组开发者集设计在贷款的可选数据库,同时另一组集中在用户界面上,而第三组集中在付款的计算上,使协调问题最小化为每一个包引入单态类,它对这个包里的对象以独占方式进行访问结构型设计模式名字所能满足的设计目标所能满足的目标的应用实例设计模式的总结Flyweight(享元)设计模式能够获得这样的好处:既能拥有许多单独的对象,又不需要过多的运行空间我们想通过模板来预览一个房间。现有五个模板模式,但是墙璧上标记着无数潜在的模板。如果每个标记都是一个独立的对象,那么就变得非常容易了,但是我们不可能提供足够的内存,同时为每个独个独立的对象命名也是不切实际的通过使用表述上下文的变量来确定方法的参数从而达到共享对象
25、的目的Proxy(代理)设计模式有些方法是远程的或者执行时需要大量的资源(时间或空间),要确保这些方法只在必要时才执行假定绘制一个图像将花费很多时间和空间,因为图像数据要从一个文件读出,写入缓冲区,然后绘制。如果缓冲区己经被先前启用的这个方法填充,那么现在启用的函数就不用重复这一步引入一个介于请求方法和资源之间的类行为型设计模式含义:每个行为模式捕获对象集合的一含义:每个行为模式捕获对象集合的一种行为种行为结构型设计模式名字所能满足的设计目标所能满足的目标的应用实例设计模式的总结Chain of Responisibility(职责链)我们需要一个能够表现功能性的对象集合。在设计时,希望能够很
26、容易地增加和删除对象,这些对象用来处理所有的或者部分的职责为Web应用程序设计一个能够根据需要的颜色来浏览汽车的GUI(图形用户接口)等等。这个显示是动态的,依赖选择的模式。重用显示中的GUI部分通过聚合使对象之间相互连接。每个对象完成一部分工作,接着调查用链上的下一个对象继续这个工作Command(指令)执行操作变得更加灵活。例如:激活“撤消”在任何时候都允许应用程序的使用者撤销最近四次的决定(所谓的“撤销”问题)捕获自己的类中每种命令Interpreter(解释器)分析一个表达式设计一个程序,把一个以标准语法表达的输入作为PC系列网络的命令,输出是一组装配网络的指令引入一个捕获表达式的类,
27、并且允许表达式类聚合表达式类Mediator(中介者)捕获对象之间的交互,这些对象彼此之间没有相互引用(因此允许它们的重用)捕获对象之间的交互,这些对象彼此之间没有相互引用(因此允许它们的重用)在聚合了所包含对象的独立类中捕获每个交互行为型设计模式名字所能满足的设计目标所能满足的目标的应用实例设计模式的总结Observer(观察者)一个对象集合依赖于某一个对象中的数据。设计一个方法,当所依赖的那个对象属性值改变时,这些对象 也能够得到相应的更新一个对象集合依赖于某一个对象中的数据。设计一个方法,当所依赖的那个对象属性值改变时,这些对象也能够得到相应的更新作为一个类来捕获数据库源。通过调用upd
28、ate()方法,允许这些数据在“观察者”对象中重复使用State(状态)在运行时,根据所依赖的对象状态的不同,启用一个方法的结果也会有所不同在运行时,根据所依赖的对象状态的不同,启用一个方法的结果也会有所不同聚合一个使用操作方法doAction()来表示状态的类:子类使用自己的doAction()版本,实现子状态需要的动作Template(模板)允许一个算法在运行时可以操作局部变量允许一个算法在运行时可以操作局部变量具备一个包含所有方法的基本础类,并且要有需要参数的函数调查用。构建子类来实现这些函数调用,捕获需要的参数港口运输停泊停泊干涸码头 障碍ShipTugboat拖船1.n1海港应用客户
29、应用:单独重用ShipShipLongshoreman港口工人避免依赖中介者概念应用到海港问题ShipTugboatLeavingPortestimateTime()估算时间在海港问题中应用中介者设计模式ShipTugboat拖船VesselPortMissionestimateTime()LeavingPort离港estimateTime()EnteringPort进港estimateTime()BeingMaintained维修estimateTime()Mediator base class你可以请求查看一种奢华的车型使用一种你可以请求查看一种奢华的车型使用一种奢华的车体风格,并且是黑色
30、的奢华的车体风格,并且是黑色的汽车类型汽车类型汽车风格 汽车颜色选择一种汽车进行显示选择一种汽车进行显示OKBasicMidsizeLuxurySUVLuxury Extra Basic Black Brown Red White这部分是固定的根据选择的类型进行选择根据选择的汽车风格进行显示假设每一种最终都会有一个动画显示结果使用职责链模式解决的设计问题关键概念:行为设计模式 在在对对象中捕象中捕获获行行为为设计模式的特征:观点、角色、层次l描述设计模式的两种观点:u静态和动态l模式的两个层次:u抽象和具体l模式使用的三个角色:模式应用、客户、建立u设计模式应用角色u 使用此应用的代码(客户角
31、色)u初始化或改变设计模式应用的代码(建立角色)设计模式的特征1l观点描述模式的方法1.静态:类模型(构造块)2.动态:顺序图或状态图(操作)l层次模式分解1.抽象层描述模式的核心2.用例的特殊性l角色 模式使用的“表演者”1.设计模式本身的应用2.设计模式应用的客户3.建立初始化和控制代码设计模式特征21.Client role2.客户任务2.Setup role 建立任务ACA.Static viewpointB.Dynamic viewpoint3.任务:设计模式的应用DB(i)Abstract level(ii)Concrete level(class model)(sequence
32、or state diagram)(class or classes)(class or classes)引用方面getWallCabinet()抽象工厂应用的顺序图抽象工厂应用的顺序图myStyle:KitchenStyleClientmyStyle:ModernKStylemyStyle:AntiqueKStylerenderKitchen(myStyle)wallCabinet1:ModernWallCabinetwallCabinet1:AntiqueWallCabinetModernWallCabinet()getWallCabinet()AntiqueWallCabinet()my
33、Style.getWallCabinet()-IF myStyle BELONGS TO ModernKStyle-IF myStyle BELONGS TO AntiqueKStyle-关键概念:两个观点 我我们们从静从静态观态观点(由什么点(由什么创创建)和建)和动态观动态观点(怎点(怎样发挥样发挥功能)两方面来考功能)两方面来考虑设计虑设计模式。模式。KitchenStyleKitchenClientModernKStyleAntiqueKStyleWallCabinet FloorCabinet ModernWallCabinetModernFloorCabinetAntiqueWal
34、lCabinetAntiqueFloorCabinetAbstract levelConcrete level模式的两个层次:抽象和具体设计目标:正确性 我们希望设计模式提供一个接口,以便使它我们希望设计模式提供一个接口,以便使它的功能性更加清楚和独立。的功能性更加清楚和独立。关键概念:两个层次 Design patterns usually have an abstract level and a non-abstract(“concrete”)level.设计设计模式通常具有抽象模式通常具有抽象层层和非抽象和非抽象层层(具体(具体层层)模式使用的三个角色l设计模式应用角色:l客户角色:程序
35、的许多部分潜在地可以使用设计模式,能常我们把这些部分看成是模式的客户;每个客户通常是一个方法,把方法的类也看成客户;客户是通过模式应用的特定类的特定方法;这些方法和类组成了应用程序的接口;l建立角色:是由运行时用来初始化或者修改模式应用的代码组成的;建立角色代码需要访问应用程序的许多部分,而且在运行时通常是集约的,并且一般不打算重用,因为它要成为应用程序的特殊部分;建立角色依赖于太多的其他 类2.Client Role客户角色客户角色1.Design Pattern Application2.设计模式本身的应用设计模式本身的应用Interface to the pattern(frequent
36、ly abstract;possibly several classes)DPClientDPInterfaceRest of thedesign patternapplicationInteracts with the design pattern only through its interface3.Setup Role建立角色建立角色 模式使用的三个角色 Rest of the Application No limitations设计模式的形式:委托与递归l委托的起源和意义 u间接性 u多态性lDelegation设计模式的形式unew AntiqueWallCabinet();u 替
37、换为:myStyle.getWallCabinet();u 实现委托的通用方法:通过一个类把功能委托给一个抽抽象类的方法。通过使用虚函数来实现委托uRecursion设计模式的形式 模式的某部分在本质上也使用了自身 委托设计模式的基本思想requiredFunction()intermediaryFunction()requiredFunction()ClientclientFunction()intermediaryFunction()replace clientFunction()intermediaryFunction()计基本模式#1:委托DoerBasedoIt()DPInterfa
38、ceinterfaceMethod()ConcreteDoer1doIt()ConcreteDoer2doIt().doerObject interfaceMethod()doerObject.doIt()Client设计基本模式#2:递归RecursionBasedoOperation()NonrecursiveClassdoOperation()RecursiveClassdoOperation()void doOperation()aggregate aggregateClient递归形式在一个组织链表中的应用EmployeeprintOrganization()IndividualCo
39、ntributorprintOrganization()SupervisorprintOrganization()void printOrganization()supervisees.printOrganization()superviseesClient关键概念:两种形式 设计设计模式的形式通常是模式的形式通常是责责任的委托或者任的委托或者是与自身相关是与自身相关联联的的类类(递归递归)小结l设计模式能实现可重现设计目标 l分为创造型、结构、行为型三类l使用静态和动态观点描述u通常分别与类模型和时序图相对应l客户角色是指设计模式应用的运用u客户接口应该小心控制u“建立”通常是指初始化,它是
40、一个独立的角色l设计模式的形式通常是委托或者递归 观察者设计模式观察者设计模式Sourcenotify()Observerupdate()ConcreteSubjectstateConcreteObserverobserverStateupdate()Trigger1.nInitialize第四部分 几个有代表性的设计模式 一、策略模式Strategy Pattern 定义一系列算法,把它们一个个封装起来,并且使它们定义一系列算法,把它们一个个封装起来,并且使它们可相互替换。本模式使得算法可独立于使用它的客户而变化。可相互替换。本模式使得算法可独立于使用它的客户而变化。1.1 概述概述1类中一
41、个方法的方法体由一系列语句构成,方法的方法体是一个算法。2比如,Army类,该类中有一个int型数组,数组元素的值代表士兵的号码,该类中有lineUp(),该方法将士兵按他们的号码从小到大排队.3Army类创建的任何对象,比如“三连长”,“四连长”等,调用lineUp()方法只能将自己所管理的士兵按其号码从小到大排队.4需求变化。需求变化可能导致经常需要修改类中某个方法的方法体,即修改算法。有些部队希望Army创建的“连长”能将士兵按着他们的号码从大到小排队(不是从小到大),或将士兵按着他们的号码的某种排列来排队。5问题出现。Army无法提供这样的对象(设计不合理).6.不正确地解决问题。痛苦
42、地修改lineUp()的方法体,但马上就发现这样做也不行,因为一旦将lineUp()的方法体修改成把士兵按着他们的号码从大到小来排队,那么又无法满足某些部队希望Army创建的“连长”能将自己的士兵从小到大排序;也许我们可以在lineUp()方法中添加多重条件语句,以便根据用户的具体需求决定怎样排队,但这也不是一个好办法,因为只要一旦有新的需求,就要修改lineUp()方法添加新的判断语句,而且针对某个条件语句的排队代码也可能因该用户的需求变化导致重新编写。7我们发现问题的实质:问题的症结就是Army类的lineUp()方法体中的代码(具体算法)需要经常地发生变化。8寻找解决办法。面向对象编程有
43、一个很好的设计原则:“面向抽象编程”,该原则的核心就是将类中经常需要变化的部分分割出来,并将每种可能的变化对应地交给抽象类的一个子类或实现接口的一个类去负责,从而让类的设计者不去关心具体实现,避免所设计的类依赖于具体的实现。现在,我们面向接口(抽象类)来重新设计现在,我们面向接口(抽象类)来重新设计ArmyArmy类,让类,让ArmyArmy类依类依赖于赖于StrategyStrategy接口,即接口,即ArmyArmy类含有一个类含有一个StrategyStrategy接口声明的变量,并接口声明的变量,并重新编写重新编写lineUplineUp()()的方法体中的代码,其主要代码是委托的方法
44、体中的代码,其主要代码是委托ArmyArmy类中的类中的StrategyStrategy接口变量调用接口变量调用arrange(intarrange(int a)a)方法,类图如图方法,类图如图1.41.4 9总结出办法:策略模式。策略模式是处理算法的不同变体的一种成熟模式,策略模式通过接口或抽象类封装算法的标识,即在接口中定义一个抽象方法,实现该接口的类将实现接口中的抽象方法。策略模式把针对一个算法标识的一系列具体算法分别封装在不同的类中,使得各个类给出的具体算法可以相互替换。在策略模式中,封装算法标识的接口称作策略,实现该接口的类称作具体策略。以下的7.2节给出策略模式的类图,并详细阐述该
45、模式中各个角色的职责。1.2 策略模式的UML类图 策略模式的结构中包括三种角色:l策略(Strategy):策略是一个接口,该接口定义若干个算法标识,即定义了若干个抽象方法。l具体策略(ConcreteStrategy):具体策略是实现策略接口的类。具体策略实现策略接口所定义的抽象方法,即给出算法标识的具体算法。l上下文(Context):上下文是依赖于策略接口的类,即上下文包含有策略声明的变量。上下文中提供一个方法,该方法委托策略变量调用具体策略所实现的策略接口中的方法。二、装饰模式Decorator Pattern l 动态地给对象添加一些额外的职责。就功能来说装饰模动态地给对象添加一些
46、额外的职责。就功能来说装饰模式相比生成子类更为灵活式相比生成子类更为灵活l1在许多设计中,可能需要改进类的某个对象的功能,而不是该类创建的全部对象。l2比如,麻雀类的实例(麻雀)能连续飞行100米,如果我们用麻雀类创建了5只麻雀,那么这5只麻雀都能连续飞行100米。l3需求变化。假如想让其中一只麻雀能连续飞行150米,那应当怎样做呢?我们不想通过修改麻雀类的代码(也可能根本不允许我们修改)使得麻雀类创建的麻雀都能连续飞行150米,这也不符合需求:改进类的某个对象的功能。l4不正确地解决问题(稍后讲)l5寻找解决办法。一种比较好的办法就是给麻雀装上智能电子翅膀。智能电子翅膀可以使得麻雀不使用自己
47、的翅膀就能飞行50米。那么一只安装了这种智能电子翅膀的麻雀就能飞行150米,因为麻雀首先使用自己的翅膀飞行100米,然后电子翅膀开始工作再飞行50米。l6正确的解决办法:装饰模式。装饰模式是动态地扩展一个对象的功能,而不需要改变原始类代码的一种成熟模式。l7关键术语。l(1)具体组件l具体组件称作“被装饰者”。l(2)具体装饰l具体装饰称为“装饰者”。l 8关键技术l“具体装饰”需要包含有“具体组件”的一个实例的引用,以便装饰“被装饰者”。如图2.1。l麻雀类就是“具体组件”,而一只麻雀就是“具体组件”的一个实例,即是一个“被装饰者”,而按装了电子翅膀的麻雀就是“具体装饰”的一个实例,即按装了
48、电子翅膀的麻雀就是麻雀的“装饰者”。l比如,麻雀类有一个fly方法,麻雀类的实例调用fly能飞行100米,如图2.2 l“具体装饰”类的fly方法“具体装饰”类的fly方法能飞行150米装饰类的eleFly方法能飞行50米麻雀类的fly方法能飞行100米。“具体装饰”类的实例调用fly麻雀类的fly方法能飞100米。调用fly图2.2 麻雀类的fly方法麻雀类的实例l “具体装饰”也有一个和麻雀类同名的fly()方法,另外还有一个自己独特的新方法eleFly()方法。由于“具体装饰”类包含有一只麻雀的引用,因此“具体装饰”类可以将它的fly()方法实现为:首先委托麻雀调用fly()方法飞行10
49、0米,然后再调用eleFly()方法飞行50米。因此,“具体装饰”类的实例调用fly()方法能飞行150米,如图2.3。2.2装饰模式的UML类图 装饰模式的结构中包括四种角色:l抽象组件(Component):抽象组件是一个抽象类。抽象组件定义了“被装饰者”需要进行“装饰”的方法。l具体组件(ConcreteComponent):具体组件是抽象组件的一个子类,具体组件的实例称作“被装饰者”。l装饰(Decorator):装饰是抽象组件的一个子类,装饰包含有一个抽象组件声明的变量以保存“被装饰者”的引用。装饰可以是抽象类也可以是一个非抽象类,如果是非抽象类,那么该类的实例称作“装饰者”。l具体
50、装饰(ConcreteDecotator):具体装饰是装饰的一个非抽象子类,具体装饰的实例称作“装饰者”。作业l1.记录设计模式包含要素有哪些?l2.解释设计模式的概念。l3.描述设计模式的两种观点分别是什么?l4.设计模式通常具有哪两个层次?l5.设计模式分为哪三种类型?l6.设计模式有哪两种形式?答案l1.记录一个设计模式需有四个基本要素:u名称名称:一个模式的名称高度概括该模式的本质,有利于该行业统一术语、便于交流使用。u问题:问题:描述应该在何时使用模式,解释设计问题和问题存在的前因后果,描述在怎样的环境下使用该模式。u方案方案:描述设计的组成部分,它们之间的相互关系及各自的职责和协作