我要投搞

标签云

收藏小站

爱尚经典语录、名言、句子、散文、日志、唯美图片

当前位置:四肖中特 > 反向复用 >

设计模式 可复用面向对象软件的基础(高清版)pdf

归档日期:06-18       文本归类:反向复用      文章编辑:爱尚语录

  1.本站不保证该用户上传的文档完整性,不预览、不比对内容而直接下载产生的反悔问题本站不予受理。

  本书设计实例从面向对象的设计中精选出 23 个设计模式,总结 了面向对象设计中最有价值的经验,并且用简洁可复用的形式表达出 来。本书分类描述了一组设计良好,表达清楚的软件设计模式,这些 模式在实用环境下有特别有用。 目 录 序言 前言 读者指南 第1 章 引言 1 1.1 什么是设计模式 2 1.2 Smalltalk MVC 中的设计模式 3 1.3 描述设计模式 4 1.4 设计模式的编目 5 1.5 组织编目 7 1.6 设计模式怎样解决设计问题 8 1.6.1 寻找合适的对象 8 1.6.2 决定对象的粒度 9 1.6.3 指定对象接口 9 1.6.4 描述对象的实现 10 1.6.5 运用复用机制 13 1.6.6 关联运行时刻和编译时刻的结构 15 1.6.7 设计应支持变化 16 1.7 怎样选择设计模式 19 1.8 怎样使用设计模式 20 第2 章 实例研究:设计一个文档编辑器 22 2.1 设计问题 23 2.2 文档结构 23 2.2.1 递归组合 24 2.2.2 图元 25 2.2.3 组合模式 27 2.3 格式化 27 2.3.1 封装格式化算法 27 2.3.2 Compositor 和Composition 27 2.3.3 策略模式 29 2.4 修饰用户界面 29 2.4.1 透明围栏 29 2.4.2 Monoglyph 30 2.4.3 Decorator 模式 32 2.5 支持多种视感标准 32 2.5.1 对象创建的抽象 32 2.5.2 工厂类和产品类 33 2.5.3 Abstract Factory 模式 35 2.6 支持多种窗口系统 35 2.6.1 我们是否可以使用Abstract Factory 模式 35 2.6.2 封装实现依赖关系 35 2.6.3 Window 和WindowImp 37 2.6.4 Bridge 模式 40 2.7 用户操作 40 2.7.1 封装一个请求 41 2.7.2 Command 类及其子类 41 2.7.3 撤消和重做 42 2.7.4 命令历史记录 42 2.7.5 Command 模式 44 2.8 拼写检查和断字处理 44 2.8.1 访问分散的信息 44 2.8.2 封装访问和遍历 45 2.8.3 Iterator 类及其子类 46 2.8.4 Iterator 模式 48 2.8.5 遍历和遍历过程中的动作 48 2.8.6 封装分析 48 2.8.7 Visitor 类及其子类 51 2.8.8 Visitor 模式 52 2.9 小结 53 第3 章 创建型模式 54 3.1 Abstract Factory (抽象工厂)—对象创建型模式 57 3.2 Builder (生成器)—对象创建型模式 63 3.3 Factory Method (工厂方法)—对象创建型模式 70 3.4 Prototype (原型)—对象创建型模式 87 3.5 Singleton (单件)—对象创建型模式 84 3.6 创建型模式的讨论 89 第4 章 结构型模式 91 4.1 Adapter (适配器)—类对象结构型模式 92 4.2 Bridge (桥接)—对象结构型模式 100 4.3 Composite (组成)—对象结构型模式 107 4.4 Decorator (装饰)—对象结构型模式 115 4.5 FACADE (外观)—对象结构型模式 121 4.6 Flyweight (享元)—对象结构型模式 128 4.7 Proxy (代理)—对象结构型模式 137 4.8 结构型模式的讨论 144 4.8.1 Adapter 与Bridge 144 4.8.2 Composite 、Decorator 与Proxy 145 第5 章 行为模式 147 5.1 CHAIN OF RESPONSIBIL ITY (职责链)—对象行为型模式 147 5.2 COMMAND (命令)—对象行为型模式 154 5.3 INTERPRETER (解释器)—类行为型模式 162 5.4 ITERATOR (迭代器)—对象行为型模式 171 5.5 MEDIATOR (中介者)—对象行为型模式 181 5.6 MEMENTO (备忘录)—对象行为型模式 188 5.7 OBSERVER (观察者)—对象行为型模式 194 5.8 STATE (状态)—对象行为型模式 201 5.9 STRATEGY (策略)—对象行为型模式 208 5.10 TEMPLATE METHOD (模板方法)—类行为型模式 214 5.11 VISITOR (访问者)—对象行为型模式 218 5.12 行为模式的讨论 228 5.12 1 封装变化 228 5.12.2 对象作为参数 228 5.12.3 通信应该被封装还是被分布 229 5.12.4 对发送者和接收者解耦 229 5.12.5 总结 231 第6 章 结论 232 6.1 设计模式将带来什么 232 6.2 一套通用的设计词汇 232 6.3 书写文档和学习的辅助手段 232 6.4 现有方法的一种补充 233 6.5 重构的目标 233 6.6 本书简史 234 6.7 模式界 235 6.8 Alexander 的模式语言 235 6.9 软件中的模式 236 6.10 邀请参与 237 6.11 临别感想 237 附录A 词汇表 238 附录B 图示符号指南 241 附录C 基本类 244 参考文献 249 序 言 所有结构良好的面向对象软件体系结构中都包含了许多模式。实际上,当我 评估一个面向对象系统的质量时,所使用的方法之一就是要判断系统的设计者是 否强调了对象之间的公共协同关系。在系统开发阶段强调这种机制的优势在于, 它能使所生成的系统体系结构更加精巧、简洁和易于理解,其程度远远超过了未 使用模式的体系结构。 模式在构造复杂系统时的重要性早已在其他领域中被认可。特别地, Christopher Alexander 和他的同事们可能最先将模式语言(pattern language )应用 于城市建筑领域,他的思想和其他人的贡献已经根植于面向对象软件界。简而言 之,软件领域中的设计模式为开发人员提供了一种使用专家设计经验的有效途 径。 在本书中,Erich Gamma 、Richard Helm、Ralph Johnson 和John Vlissides 介 绍了设计模式的原理,并且对这些设计模式进行了分类描述。因此,该书做出了 两个重要的贡献:首先,它展示了模式在建造复杂系统过程中所处的角色;其次, 它为如何引用一组精心设计的模式提供了一个实用方法,以帮助实际开发者针对 特定应用问题使用适当的模式进行设计。 我曾荣幸地有机会与本书的部分作者一同进行体系结构设计工作,从他们身 上我学到了许多东西,并相信通过阅读该书你同样也会受益匪浅。 Rational 软件公司首席科学家 Grady Booch 前 言 本书并不是一本介绍面向对象技术或设计的书,目前已有不少好书介绍面向 对象技术或设计。本书假设你至少已经比较熟悉一种面向对象编程语言,并且有 一定的面向对象设计经验。当我们提及“类型”和“多态”,或“接口”继承与 “实现”继承的关系时,你应该对这些概念了然于胸,而不必迫不及待地翻阅手 头的字典。 另外,这也不是一篇高级专题技术论文,而是一本关于设计模式的书,它描 述了在面向对象软件设计过程中针对特定问题的简洁而优雅的解决方案。设计模 式捕获了随时间进化与发展的问题的求解方法,因此它们并不是人们从一开始就 采用的设计方案。它们反映了不为人知的重新设计和重新编码的成果,而这些都 来自软件开发者为了设计出灵活可复用的软件而长时间进行的艰苦努力。设计模 式捕获了这些解决方案,并用简洁易用的方式表达出来。 设计模式并不要求使用独特的语言特性,也不采用那些足以使你的朋友或老 板大吃一惊的神奇的编程技巧。所有的模式均可以用标准的面向对象语言实现, 这也许有时会比特殊的解法多费一些功夫,但是为了增加软件的灵活性和可复用 性,多做些工作是值得的。 一旦你理解了设计模式并且有了一种“Aha !”(而不是“Huh ?”)的应用经 验和体验后,你将用一种非同寻常的方式思考面向对象设计。你将拥有一种深刻 的洞察力,以帮助你设计出更加灵活的、模块化的、可复用的和易理解的软件— 这也是你为何着迷于面向对象技术的源动力,不是吗? 当然还有一些提示和鼓励:第一次阅读此书时你可能不会完全理解它,但不 必着急,我们在起初编写这本书时也没有完全理解它们!请记住,这不是一本读 完一遍就可以束之高阁的书。我们希望你在软件设计过程中反复参阅此书,以获 取设计灵感。 我们并不认为这组设计模式是完整的和一成不变的,它只是我们目前对设计 的思考的记录。因此我们欢迎广大读者的批评与指正,无论从书中采用的实例、 参考,还是我们遗漏的已知应用,或应该包含的设计模式等方面。你可以通过 Addison-Wesley 写信给我们,或发送电子邮件到:design-patterns@ 。 你 还 可 以 发 送 邮 件 “ send design pattern source ” 到 design-patterns-source@ 获取书中的示例代码部分的源代码。 另外我们有一个专门的网页报道最新的消息与更新: /users/patterns/DPBook/DPBook.html. E.G. 于加州Mountain View R.H. 于蒙特利尔 R.J. 于伊利诺Urbana J.V. 于纽约 Hawthorne 1994 年8 月 下载 第1章 引 言 设计面向对象软件比较困难,而设计可复用 的面向对象软件就更加困难。你必须找到相 关的对象,以适当的粒度将它们归类,再定义类的接口和继承层次,建立对象之间的基本关 系。你的设计应该对手头的问题有针对性,同时对将来的问题和需求也要有足够的通用性。 你也希望避免重复设计或尽可能少做重复设计。有经验的面向对象设计者会告诉你,要一下 子就得到复用性和灵活性好的设计,即使不是不可能的至少也是非常困难的。一个设计在最 终完成之前常要被复用好几次,而且每一次都有所修改。 有经验的面向对象设计者的确能做出良好的设计,而新手则面对众多选择无从下手,总 是求助于以前使用过的非面向对象技术。新手需要花费较长时间领会良好的面向对象设计是 怎么回事。有经验的设计者显然知道一些新手所不知道的东西,这又是什么呢? 内行的设计者知道:不是解决任何问题都要从头做起。他们更愿意复用以前使用过的解 决方案。当找到一个好的解决方案,他们会一遍又一遍地使用。这些经验是他们成为内行的 部分原因。因此,你会在许多面向对象系统中看到类和相互通信的对象( c o m m u n i c a t i n g o b j e c t )的重复模式。这些模式解决特定的设计问题,使面向对象设计更灵活、优雅,最终复 用性更好。它们帮助设计者将新的设计建立在以往工作的基础上,复用以往成功的设计方案。 一个熟悉这些模式的设计者不需要再去发现它们,而能够立即将它们应用于设计问题中。 以下类比可以帮助说明这一点。小说家和剧本作家很少从头开始设计剧情。他们总是沿 袭一些业已存在的模式,像“悲剧性英雄”模式 ( 《麦克白》、《哈姆雷特》等)或“浪漫小说” 模式(存在着无数浪漫小说) 。同样地,面向对象设计员也沿袭一些模式,像“用对象表示状态” 和“修饰对象以便于你能容易地添加 /删除属性”等。一旦懂得了模式,许多设计决策自然而 然就产生了。 我们都知道设计经验的重要价值。你曾经多少次有过这种感觉—你已经解决过了一个问 题但就是不能确切知道是在什么地方或怎么解决的?如果你能记起以前问题的细节和怎么解 决它的,你就可以复用以前的经验而不需要重新发现它。然而,我们并没有很好记录下可供 他人使用的软件设计经验。 这本书的目的就是将面向对象软件的设计经验作为设计模式记录下来。每一个设计模式 系统地命名、解释和评价了面向对象系统中一个重要的和重复出现的设计。我们的目标是将 设计经验以人们能够有效利用的形式记录下来。鉴于此目的,我们编写了一些最重要的设计 模式,并以编目分类的形式将它们展现出来。 设计模式使人们可以更加简单方便地复用成功的设计和体系结构。将已证实的技术表述 成设计模式也会使新系统开发者更加容易理解其设计思路。设计模式帮助你做出有利于系统 复用的选择,避免设计损害了系统复用性。通过提供一个显式类和对象作用关系以及它们之 间潜在联系的说明规范,设计模式甚至能够提高已有系统的文档管理和系统维护的有效性。 简而言之,设计模式可以帮助设计者更快更好地完成系统设计。 本书中涉及的设计模式并不描述新的或未经证实的设计,我们只收录那些在不同系统中 2 设计模式 :可复用面向对象软件的基础 下载 多次使用过的成功设计。这些设计的绝大部分以往并无文档记录,它们或是来源于面向对象 设计者圈子里的非正式交流,或是来源于某些成功的面向对象系统的某些部分,但对设计新 手来说,这些东西是很难学得到的。尽管这些设计不包含新的思路,但我们用一种新的、便 于理解的方式将其展现给读者,即:具有统一格式的、已分类编目的若干组设计模式。 尽管该书涉及较多的内容,但书中讨论的设计模式仅仅包含了一个设计行家所知道的部 分。书中没有讨论与并发或分布式或实时程序设计有关的模式,也没有收录面向特定应用领 域的模式。本书并不准备告诉你怎样构造用户界面、怎样写设备驱动程序或怎样使用面向对 象数据库,这些方面都有自己的模式,将这些模式分类编目也是件很有意义的事。 1.1 什么是设计模式 Christopher Alexander 说过:“每一个模式描述了一个在我们周围不断重复发生的问题, 以及该问题的解决方案的核心。这样,你就能一次又一次地使用该方案而不必做重复劳动” [ A I S + 7 7 ,第1 0页] 。尽管A l e x a n d e r所指的是城市和建筑模式,但他的思想也同样适用于面向 对象设计模式,只是在面向对象的解决方案里,我们用对象和接口代替了墙壁和门窗。两类 模式的核心都在于提供了相关问题的解决方案。 一般而言,一个模式有四个基本要素: 1. 模式名称 (pattern name ) 一个助记名,它用一两个词来描述模式的问题、解决方案 和效果。命名一个新的模式增加了我们的设计词汇。设计模式允许我们在较高的抽象层次上 进行设计。基于一个模式词汇表,我们自己以及同事之间就可以讨论模式并在编写文档时使 用它们。模式名可以帮助我们思考,便于我们与其他人交流设计思想及设计结果。找到恰当 的模式名也是我们设计模式编目工作的难点之一。 2. 问题(problem) 描述了应该在何时使用模式。它解释了设计问题和问题存在的前因后 果,它可能描述了特定的设计问题,如怎样用对象表示算法等。也可能描述了导致不灵活设 计的类或对象结构。有时候,问题部分会包括使用模式必须满足的一系列先决条件。 3. 解决方案(solution) 描述了设计的组成成分,它们之间的相互关系及各自的职责和协 作方式。因为模式就像一个模板,可应用于多种不同场合,所以解决方案并不描述一个特定 而具体的设计或实现,而是提供设计问题的抽象描述和怎样用一个具有一般意义的元素组合 (类或对象组合)来解决这个问题。 4. 效果(consequences) 描述了模式应用的效果及使用模式应权衡的问题。尽管我们描述 设计决策时,并不总提到模式效果,但它们对于评价设计选择和理解使用模式的代价及好处 具有重要意义。软件效果大多关注对时间和空间的衡量,它们也表述了语言和实现问题。因 为复用是面向对象设计的要素之一,所以模式效果包括它对系统的灵活性、扩充性或可移植 性的影响,显式地列出这些效果对理解和评价这些模式很有帮助。 出发点的不同会产生对什么是模式和什么不是模式的理解不同。一个人的模式对另一个 人来说可能只是基本构造部件。本书中我们将在一定的抽象层次上讨论模式。《设计模式》并 不描述链表和h a s h表那样的设计,尽管它们可以用类来封装,也可复用;也不包括那些复杂 的、特定领域内的对整个应用或子系统的设计。本书中的设计模式是对被用来在特定场景下 解决一般设计问题的类和相互通信的对象的描述 。 一个设计模式命名、抽象和确定了一个通用设计结构的主要方面,这些设计结构能被用 第1章 引 言 3 下载 来构造可复用的面向对象设计。设计模式确定了所包含的类和实例,它们的角色、协作方式 以及职责分配。每一个设计模式都集中于一个特定的面向对象设计问题或设计要点,描述了 什么时候使用它,在另一些设计约束条件下是否还能使用,以及使用的效果和如何取舍。既 然我们最终要实现设计,设计模式还提供了 C++ 和S m a l l t a l k示例代码来阐明其实现。 虽然设计模式描述的是面向对象设计,但它们都基于实际的解决方案,这些方案的实现 语言是Smalltalk 和C + +等主流面向对象编程语言,而不是过程式语言 ( P a s c a l 、C、A d a )或更具 动态特性的面向对象语言 ( C L O S 、D y l a n 、S e l f ) 。我们从实用角度出发选择了Smalltalk 和C + + , 因为在这些语言的使用上,我们积累了许多经验,况且它们也变得越来越流行。 程序设计语言的选择非常重要,它将影响人们理解问题的出发点。我们的设计模式采用了 Smalltalk 和C + +层的语言特性,这个选择实际上决定了哪些机制可以方便地实现,而哪些则 不能。若我们采用过程式语言,可能就要包括诸如“继承”、“封装”和“多态”的设计模式。 相应地,一些特殊的面向对象语言可以直接支持我们的某些模式,例如: C L O S支持多方法 (m u l t i - m e t h o d )概念,这就减少了Vi s i t o r模式的必要性。事实上, S m a l l t a l k和C + + 已有足够的 差别来说明对某些模式一种语言比另一种语言表述起来更容易一些 (参见5 . 4节Iterator 模式) 。 1.2 Smalltalk MVC中的设计模式 在S m a l l t a l k - 8 0 中,类的模型/ 视图/控制器(M o d e l / Vi e w / C o n t r o l l e r )三元组( M V C )被用来 构建用户界面。透过MVC 来看设计模式将帮助我们理解“模式”这一术语的含义。 M V C包括三类对象。模型 M o d e l 是应用对象,视图 Vi e w 是它在屏幕上的表示,控制器 C o n t r o l l e r定义用户界面对用户输入的响应方式。不使用 M V C ,用户界面设计往往将这些对象 混在一起,而M V C则将它们分离以提高灵活性和复用性。 M V C通过建立一个“订购 /通知”协议来分离视图和模型。视图必须保证它的显示正确地 反映了模型的状态。一旦模型的数据发生变化,模型将通知有关的视图,每个视图相应地得 到刷新自己的机会。这种方法可以让你为一个模型提供不同的多个视图表现形式,也能够为 一个模型创建新的视图而无须重写模型。 下图显示了一个模型和三个视图(为了简单起见我们省略了控制器)。模型包含一些数据 值,视图通过电子表格、柱状图、饼图这些不同的方式来显示这些数据。当模型的数据发生 变化时,模型就通知它的视图,而视图将与模型通信以访问这些数据值。 视图 模型 4 设计模式 :可复用面向对象软件的基础 下载 表面上看,这个例子反映了将视图和模型分离的设计,然而这个设计还可用于解决更一 般的问题:将对象分离,使得一个对象的改变能够影响另一些对象,而这个对象并不需要知 道那些被影响的对象的细节。这个更一般的设计被描述成 O b s e r v e r (5 . 7 )模式。 M V C 的另一个特征是视图可以嵌套。例如,按钮控制面板可以用一个嵌套了按钮的复杂 视图来实现。对象查看器的用户界面可由嵌套的视图构成,这些视图又可复用于调试器。 M V C用Vi e w类的子类—C o m p o s i t e Vi e w类来支持嵌套视图。 C o m p o s i t e Vi e w类的对象行为上 类似于Vi e w类对象,一个组合视图可用于任何视图可用的地方,但是它包含并管理嵌套视图。 上例反映了可以将组合视图与其构件平等对待的设计,同样地,该设计也适用于更一般 的问题:将一些对象划为一组,并将该组对象当作一个对象来使用。这个设计被描述为 C o m p o s i t e (4 . 3 )模式,该模式允许你创建一个类层次结构,一些子类定义了原子对象(如 B u t t o n )而其他类定义了组合对象( C o m p o s i t e Vi e w ),这些组合对象是由原子对象组合而成 的更复杂的对象。 M V C 允许你在不改变视图外观的情况下改变视图对用户输入的响应方式。例如,你可能 希望改变视图对键盘的响应方式,或希望使用弹出菜单而不是原来的命令键方式。 M V C将响 应机制封装在C o n t r o l l e r对象中。存在着一个 C o n t r o l l e r 的类层次结构,使得可以方便地对原有 C o n t r o l l e r做适当改变而创建新的C o n t r o l l e r 。 Vi e w使用C o n t r o l l e r子类的实例来实现一个特定的响应策略。要实现不同的响应策略只要 用不同种类的C o n t r o l l e r实例替换即可。甚至可以在运行时刻通过改变 Vi e w 的C o n t r o l l e r来改变 Vi e w对用户输入的响应方式。例如,一个 Vi e w可以被禁止接收任何输入,只需给它一个忽略 输入事件的C o n t r o l l e r 。 Vi e w - C o n t r o l l e r关系是S t r a t e g y (5 . 9 )模式的一个例子。一个策略是一个表述算法的对象。 当你想静态或动态地替换一个算法,或你有很多不同的算法,或算法中包含你想封装的复杂 数据结构,这时策略模式是非常有用的。 M V C还使用了其他的设计模式,如:用来指定视图缺省控制器的 Factory Method(3.3) 和 用来增加视图滚动的 D e c o r a t o r ( 4 . 4 ) 。但是M V C 的主要关系还是由 O b s e r v e r 、C o m p o s i t e和 S t r a t e g y三个设计模式给出的。 1.3 描述设计模式 我们怎样描述设计模式呢?图形符号虽然很重要也很有用,却还远远不够,它们只是将 设计过程的结果简单记录为类和对象之间的关系。为了达到设计复用,我们必须同时记录设 计产生的决定过程、选择过程和权衡过程。具体的例子也是很重要的,它们让你看到实际的 设计。 我们将用统一的格式描述设计模式,每一个模式根据以下的模板被分成若干部分。模板 具有统一的信息描述结构,有助于你更容易地学习、比较和使用设计模式。 模式名和分类 模式名简洁地描述了模式的本质。一个好的名字非常重要,因为它将成为你的设计词汇 表中的一部分。模式的分类反映了我们将在 1 . 5节介绍的方案。 意图 是回答下列问题的简单陈述:设计模式是做什么的?它的基本原理和意图是什么?它解 第1章 引 言 5 下载 决的是什么样的特定设计问题? 别名 模式的其他名称。 动机 用以说明一个设计问题以及如何用模式中的类、对象来解决该问题的特定情景。该情景 会帮助你理解随后对模式更抽象的描述。 适用性 什么情况下可以使用该设计模式?该模式可用来改进哪些不良设计?你怎样识别这些情 况? 结构 采用基于对象建模技术( O M T )[ R B P + 9 1 ] 的表示法对模式中的类进行图形描述。我们也 使用了交互图 [ J C J O 9 2,B O O 9 4 ]来说明对象之间的请求序列和协作关系。附录 B 详细描述了 这些表示法。 参与者 指设计模式中的类和/或对象以及它们各自的职责。 协作 模式的参与者怎样协作以实现它们的职责。 效果 模式怎样支持它的目标?使用模式的效果和所需做的权衡取舍?系统结构的哪些方面可 以独立改变? 实现 实现模式时需要知道的一些提示、技术要点及应避免的缺陷,以及是否存在某些特定于 实现语言的问题。 代码示例 用来说明怎样用C + +或S m a l l t a l k实现该模式的代码片段。 已知应用 实际系统中发现的模式的例子。每个模式至少包括了两个不同领域的实例。 相关模式 与这个模式紧密相关的模式有哪些?其间重要的不同之处是什么?这个模式应与哪些其 他模式一起使用? 附录提供的背景资料将帮助你理解模式以及关于模式的讨论。附录 A给出了我们使用的术 语列表。前面已经提到过的附录 B 则给出了各种表示法,我们也会在以后的讨论中简单介绍它 们。最后,附录C给出了我们在例子中使用的各基本类的源代码。 1.4 设计模式的编目 从第3章开始的模式目录中共包含 2 3个设计模式。它们的名字和意图列举如下,以使你有 个基本了解。每个模式名后括号中标出模式所在的章节 (我们整本书都将遵从这个约定 ) 。 Abstract Factory ( 3 . 1 ) :提供一个创建一系列相关或相互依赖对象的接口,而无需指定它 们具体的类。 6 设计模式 :可复用面向对象软件的基础 下载 A d a p t er ( 4 . 1 ) :将一个类的接口转换成客户希望的另外一个接口。 A d a p t e r模式使得原本 由于接口不兼容而不能一起工作的那些类可以一起工作。 B r i d g e( 4 . 2 ) :将抽象部分与它的实现部分分离,使它们都可以独立地变化。 B u i l d e r( 3 . 2 ) :将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不 同的表示。 Chain of Responsibility( 5 . 1 ) :为解除请求的发送者和接收者之间耦合,而使多个对象都 有机会处理这个请求。将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象 处理它。 C o m m a n d( 5 . 2 ) :将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数 化;对请求排队或记录请求日志,以及支持可取消的操作。 C o m p o s i t e( 4 . 3 ) :将对象组合成树形结构以表示“部分 -整体”的层次结构。C o m p o s i t e使 得客户对单个对象和复合对象的使用具有一致性。 D e c o r a t o r( 4 . 4 ) :动态地给一个对象添加一些额外的职责。就扩展功能而言, D e c o r a t o r模 式比生成子类方式更为灵活。 F a c a d e( 4 . 5 ) :为子系统中的一组接口提供一个一致的界面, F a c a d e模式定义了一个高层 接口,这个接口使得这一子系统更加容易使用。 Factory Method( 3 . 3 ) :定义一个用于创建对象的接口,让子类决定将哪一个类实例化。 Factory Method使一个类的实例化延迟到其子类。 F l y w e i g h t( 4 . 6 ) :运用共享技术有效地支持大量细粒度的对象。 I n t e r p r e t e r( 5 . 3 ) :给定一个语言, 定义它的文法的一种表示,并定义一个解释器 , 该解释 器使用该表示来解释语言中的句子。 I t e r a t o r( 5 . 4 ) :提供一种方法顺序访问一个聚合对象中各个元素 , 而又不需暴露该对象的 内部表示。 M e d i a t o r( 5 . 5 ) :用一个中介对象来封装一系列的对象交互。中介者使各对象不需要显式 地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互。 M e m e n t o( 5 . 6 ) :在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外 保存这个状态。这样以后就可将该对象恢复到保存的状态。 O b s e r v e r( 5 . 7 ) :定义对象间的一种一对多的依赖关系 , 以便当一个对象的状态发生改变时, 所有依赖于它的对象都得到通知并自动刷新。 P r o t o t y p e( 3 . 4 ) :用原型实例指定创建对象的种类,并且通过拷贝这个原型来创建新的对 象。 P r o x y( 4 . 7 ) :为其他对象提供一个代理以控制对这个对象的访问。 S i n g l e t o n( 3 . 5 ) :保证一个类仅有一个实例,并提供一个访问它的全局访问点。 S t a t e( 5 . 8 ) :允许一个对象在其内部状态改变时改变它的行为。对象看起来似乎修改了它 所属的类。 S t r a t e g y (5 . 9 ) :定义一系列的算法,把它们一个个封装起来 , 并且使它们可相互替换。本模 式使得算法的变化可独立于使用它的客户。 Template Method( 5 . 1 0 ) :定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。 Template Method使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。 第1章 引 言 7 下载 Vi s i t o r( 5 . 11 ) :表示一个作用于某对象结构中的各元素的操作。它使你可以在不改变各元 素的类的前提下定义作用于这些元素的新操作。 1.5 组织编目 设计模式在粒度和抽象层次上各不相同。由于存在众多的设计模式,我们希望用一种方 式将它们组织起来。这一节将对设计模式进行分类以便于我们对各族相关的模式进行引用。 分类有助于更快地学习目录中的模式,且对发现新的模式也有指导作用,如表1 - 1所示。 表1-1 设计模式空间 目 的 创 建 型 结 构 型 行 为 型 范围 类 Factory Method(3.3) A d a p t e r (类) ( 4 . 1 ) I n t e r p r e t e r ( 5 . 3 ) Template Method(5.10) 对象 Abstract Factory(3.1) A d a p t e r (对象) ( 4 . 1 ) Chain of Responsibility(5.1) B u i l d e r ( 3 . 2 ) B r i d g e ( 4 . 2 ) C o m m a n d ( 5 . 2 ) P r o t o t y p e ( 3 . 4 ) C o m p o s i t e ( 4 . 3 ) I t e r a t o r ( 5 . 4 ) S i n g l e t o n ( 3 . 5 ) D e c o r a t o r ( 4 . 4 ) M e d i a t o r ( 5 . 5 ) F a c a d e ( 4 . 5 ) M e m e n t o ( 5 . 6 ) F l y w e i g h t ( 4 . 6 ) O b s e r v e r ( 5 . 7 ) P r o x y ( 4 . 7 ) S t a t e ( 5 . 8 ) S t r a t e g y ( 5 . 9 ) Vi s i t o r ( 5 . 1 0 ) 我们根据两条准则 (表1 - 1 )对模式进行分类。第一是 目的准则,即模式是用来完成什么工 作的。模式依据其目的可分为 创建型 (C r e a t i o n a l )、结构型 ( S t r u c t u r a l ) 、或 行为型 ( B e h a v i o r a l )三种。创建型模式与对象的创建有关;结构型模式处理类或对象的组合;行为型 模式对类或对象怎样交互和怎样分配职责进行描述。 第二是 范围准则,指定模式主要是用于类还是用于对象。类模式处理类和子类之间的关 系,这些关系通过继承建立,是静态的,在编译时刻便确定下来了。对象模式处理对象间的 关系,这些关系在运行时刻是可以变化的,更具动态性。从某种意义上来说,几乎所有模式 都使用继承机制,所以“类模式”只指那些集中于处理类间关系的模式,而大部分模式都属 于对象模式的范畴。 创建型类模式将对象的部分创建工作延迟到子类,而创建型对象模式则将它延迟到另一 个对象中。结构型类模式使用继承机制来组合类,而结构型对象模式则描述了对象的组装方 式。行为型类模式使用继承描述算法和控制流,而行为型对象模式则描述一组对象怎样协作 完成单个对象所无法完成的任务。 还有其他组织模式的方式。有些模式经常会被绑在一起使用,例如, C o m p o s i t e 常和 I t e r a t o r 或Vi s i t o r 一起使用;有些模式是可替代的,例如, P r o t o t y p e 常用来替代 A b s t r a c t F a c t o r y ;有些模式尽管使用意图不同,但产生的设计结果是很相似的,例如, C o m p o s i t e和 D e c o r a t o r 的结构图是相似的。 还有一种方式是根据模式的“相关模式”部分所描述的它们怎样互相引用来组织设计模 式。图1 - 1给出了模式关系的图形说明。 8 设计模式 :可复用面向对象软件的基础 下载 显然,存在着许多组织设计模式的方法。从多角度去思考模式有助于对它们的功能、差 异和应用场合的更深入理解。 保存迭代状态 避免滞后 创建组合 枚举子女 给对象增加职责 使用组合命令 共享组合 定义遍历 定义链 增加操作 定义语法 改变外表 改变内容 增加操作 共享策略 共享终结符 共享状态 定义算法步骤 动态地配置工厂 用工厂方法实现 单个实例 单个实例 图1-1 设计模式之间的关系 1.6 设计模式怎样解决设计问题 设计模式采用多种方法解决面向对象设计者经常碰到的问题。这里给出几个问题以及使 用设计模式解决它们的方法。 1.6.1 寻找合适的对象 面向对象程序由对象组成,对象包括数据和对数据进行操作的过程,过程通常称为方法 或操作。对象在收到客户的请求(或消息)后,执行相应的操作。 第1章 引 言 9 下载 客户请求是使对象执行操作的唯一方法,操作又是对象改变内部数据的唯一方法。由于 这些限制,对象的内部状态是被封装 的,它不能被直接访问,它的表示对于对象外部是不可 见的。 面向对象设计最困难的部分是将系统分解成对象集合。因为要考虑许多因素:封装、粒 度、依赖关系、灵活性、性能、演化、复用等等,它们都影响着系统的分解,并且这些因素 通常还是互相冲突的。 面向对象设计方法学支持许多设计方法。你可以写出一个问题描述,挑出名词和动词, 进而创建相应的类和操作;或者,你可以关注于系统的协作和职责关系;或者,你可以对现 实世界建模,再将分析时发现的对象转化至设计中。至于哪一种方法最好,并无定论。 设计的许多对象来源于现实世界的分析模型。但是,设计结果所得到的类通常在现实世 界中并不存在,有些是像数组之类的低层类,而另一些则层次较高。例如, C o m p o s i t e ( 4 . 3 )模 式引入了统一对待现实世界中并不存在的对象的抽象方法。严格反映当前现实世界的模型并 不能产生也能反映将来世界的系统。设计中的抽象对于产生灵活的设计是至关重要的。 设计模式帮你确定并不明显的抽象和描述这些抽象的对象。例如,描述过程或算法的对 象现实中并不存在,但它们却是设计的关键部分。 S t r a t e g y ( 5 . 9 )模式描述了怎样实现可互换的 算法族。S t a t e ( 5 . 8 )模式将实体的每一个状态描述为一个对象。这些对象在分析阶段,甚至在 设计阶段的早期都并不存在,后来为使设计更灵活、复用性更好才将它们发掘出来。 1.6.2 决定对象的粒度 对象在大小和数目上变化极大。它们能表示下自硬件或上自整个应用的任何事物。那么 我们怎样决定一个对象应该是什么呢? 设计模式很好地讲述了这个问题。 F a c a d e ( 4 . 5 ) 模式描述了怎样用对象表示完整的子系统, F l y w e i g h t ( 4 . 6 )模式描述了如何支持大量的最小粒度的对象。其他一些设计模式描述了将一个 对象分解成许多小对象的特定方法。 Abstract Factory(3.1) 和B u i l d e r ( 3 . 2 )产生那些专门负责生 成其他对象的对象。Vi s i t o r ( 5 . 1 0 )和C o m m a n d ( 5 . 2 )生成的对象专门负责实现对其他对象或对象 组的请求。 1.6.3 指定对象接口 对象声明的每一个操作指定操作名、作为参数的对象和返回值,这就是所谓的操作的型 构( s i g n a t u r e ) 。对象操作所定义的所有操作型构的集合被称为该对象的接口( i n t e r f a c e ) 。对象 接口描述了该对象所能接受的全部请求的集合,任何匹配对象接口中型构的请求都可以发送 给该对象。 类型(type) 是用来标识特定接口的一个名字。如果一个对象接受“ Wi n d o w ”接口所定义 的所有操作请求,那么我们就说该对象具有“ Wi n d o w ”类型。一个对象可以有许多类型,并 且不同的对象可以共享同一个类型。对象接口的某部分可以用某个类型来刻画,而其他部分 则可用其他类型刻画。两个类型相同的对象只需要共享它们的部分接口。接口可以包含其他 接口作为子集。当一个类型的接口包含另一个类型的接口时,我们就说它是另一个类型的子 类型( s u b t y p e ) ,另一个类型称之为它的超类型( s u p e r t y p e ) 。我们常说子类型继承 了它的超类型 的接口。 1 0 设计模式 :可复用面向对象软件的基础 下载 在面向对象系统中,接口是基本的组成部分。对象只有通过它们的接口才能与外部交流, 如果不通过对象的接口就无法知道对象的任何事情,也无法请求对象做任何事情。对象接口 与其功能实现是分离的,不同对象可以对请求做不同的实现,也就是说,两个有相同接口的 对象可以有完全不同的实现。 当给对象发送请求时,所引起的具体操作既与请求本身有关又与接受对象有关。支持相 同请求的不同对象可能对请求激发的操作有不同的实现。发送给对象的请求和它的相应操作 在运行时刻的连接就称之为动态绑定(dynamic binding) 。 动态绑定是指发送的请求直到运行时刻才受你的具体的实现的约束。因而,在知道任何 有正确接口的对象都将接受此请求时,你可以写一个一般的程序,它期待着那些具有该特定 接口的对象。进一步讲,动态绑定允许你在运行时刻彼此替换有相同接口的对象。这种可替 换性就称为多态( p o l y m o r p h i s m ) ,它是面向对象系统中的核心概念之一。多态允许客户对象仅 要求其他对象支持特定接口,除此之外对其假设几近于无。多态简化了客户的定义,使得对 象间彼此独立,并可以在运行时刻动态改变它们相互的关系。 设计模式通过确定接口的主要组成成分及经接口发送的数据类型,来帮助你定义接口。 设计模式也许还会告诉你接口中不应包括哪些东西。 M e m e n t o ( 5 . 6 )模式是一个很好的例子, 它描述了怎样封装和保存对象内部的状态,以便一段时间后对象能恢复到这一状态。它规定 了M e m e n t o对象必须定义两个接口:一个允许客户保持和复制 m e m e n t o 的限制接口,和一个只 有原对象才能使用的用来储存和提取 m e m e n t o 中状态的特权接口。 设计模式也指定了接口之间的关系。特别地,它们经常要求一些类具有相似的接口;或 它们对一些类的接口做了限制。例如, D e c o r a t o r ( 4 . 4 )和P r o x y ( 4 . 7 )模式要求D e c o r a t o r和P r o x y 对象的接口与被修饰的对象和受委托的对象一致。而 Vi s i t o r ( 5 . 11 )模式中,Vi s i t o r接口必须反 映出v i s i t o r 能访问的对象的所有类。 1.6.4 描述对象的实现 至此,我们很少提及到实际上怎么去定义一个对象。对象的实现 是由它的类决定的,类指定了对象的内部数据和表示,也定义了对象 所能完成的操作,如右图所示。 我们基于O M T 的表示法,将类描述成一个矩形,其中的类名以黑 体表示的。操作在类名下面,以常规字体表示。类所定义的任何数据 都在操作的下面。类名与操作之间以及操作与数据之间用横线分割。 返回类型和实例变量类型是可选的,因为我们并未假设一定要用具有静态类型的实现语 言。 对象通过实例化类来创建,此对象被称为该类的实例。当实例化类时,要给对象的内部 数据( 由实例变量组成)分配存储空间,并将操作与这些数据联系起来。对象的许多类似实例是 由实例化同一个类来创建的。 下图中的虚箭头线表示一个类实例化另一个类的对象,箭头指向被实例化的对象的类。 新的类可以由已存在的类通过类继承(class inheritance)来定义。当子类( s u b c l a s s )继承父类 第1章 引 言 1 1 下载 (parent class) 时,子类包含了父类定义的所有数据和操作。子类的实例对象包含所有子类和父 类定义的数据,且它们能完成子类和父类定义的所有操作。我们以竖线和三角表示子类关系, 如下图所示。 抽象类(abstract class) 的主要目的是为它的子类定义公共接口。一个抽象类将把它的部分 或全部操作的实现延迟到子类中,因此,一个抽象类不能被实例化。在抽象类中定义却没有 实现的操作被称为抽象操作(abstract operation) 。非抽象类称为具体类(concrete class) 。 子类能够改进和重新定义它们父类的操作。更具体地说,类能够重定义( o v e r r i d e )父类定 义的操作,重定义使得子类能接管父类对请求的处理操作。类继承允许你只需简单的扩展其 他类就可以定义新类,从而可以很容易地定义具有相近功能的对象族。 抽象类的类名以斜体表示,以与具体类相区别。抽象操作也用斜体表示。图中可以包括 实现操作的伪代码,如果这样,则代码将出现在带有摺角的框中,并用虚线将该摺角框与代 码所实现的操作相连,图示如下。 混入类(mixin class)是给其他类提供可选择的接口或功能的类。它与抽象类一样不能实例 化。混入类要求多继承,图示如下。 1. 类继承与接口继承的比较 理解对象的类 ( c l a s s )与对象的类型 ( t y p e )之间的差别非常重要。 一个对象的类定义了对象是怎样实现的,同时也定义了对象的内部状态和操作的实现。 但是对象的类型只与它的接口有关,接口即对象能响应的请求的集合。一个对象可以有多个 1 2 设计模式 :可复用面向对象软件的基础 下载 类型,不同类的对象可以有相同的类型。 当然,对象的类和类型是有紧密关系的。因为类定义了对象所能执行的操作,也定义了 对象的类型。当我们说一个对象是一个类的实例时,即指该对象支持类所定义的接口。 C + +和E i ff e l语言的类既指定对象的类型又指定对象的实现。 S m a l l t a l k程序不声明变量的 类型,所以编译器不检查赋给变量的对象类型是否是该变量的类型的子类型。发送消息时需 要检查消息接收者是否实现了该消息,但不检查接收者是否是某个特定类的实例。 理解类继承和接口继承 (或子类型化)之间的差别也十分重要。类继承根据一个对象的实现 定义了另一个对象的实现。简而言之,它是代码和表示的共享机制。然而,接口继承 (或子类 型化)描述了一个对象什么时候能被用来替代另一个对象。 因为许多语言并不显式地区分这两个概念,所以容易被混淆。在 C + +和E i ff e l语言中,继 承既指接口的继承又指实现的继承。 C + + 中接口继承的标准方法是公有继承一个含 (纯)虚成员 函数的类。C + + 中纯接口继承接近于公有继承纯抽象类,纯实现继承或纯类继承接近于私有 继承。 S m a l l t a l k 中的继承只指实现继承。只要任何类的实例支持对变量值的操作,你就可以 将这些实例赋给变量。 尽管大部分程序设计语言并不区分接口继承和实现继承的差别,但使用中人们还是分别 对待它们的。 S m a l l t a l k程序员通常将子类当作子类型 (尽管有一些熟知的例外情况 [ C o o 9 2 ] ) , C + +程序员通过抽象类所定义的类型来操纵对象。 很多设计模式依赖于这种差别。例如, Chain of Responsibility(5.1)模式中的对象必须有一 个公共的类型,但一般情况下它们不具有公共的实现。在 C o m p o s i t e ( 4 . 3 )模式中,构件定义了 一个公共的接口,但 C o m p o s i t e通常定义一个公共的实现。 C o m m a n d ( 5 . 2 ) 、O b s e r v e r ( 5 . 7 ) 、 S t a t e ( 5 . 8 )和S t r a t e g y ( 5 . 9 )通常纯粹作为接口的抽象类来实现。 2. 对接口编程,而不是对实现编程 类继承是一个通过复用父类功能而扩展应用功能的基本机制。它允许你根据旧对象快速 定义新对象。它允许你从已存在的类中继承所需要的绝大部分功能,从而几乎无需任何代价 就可以获得新的实现。 然而,实现的复用只是成功的一半,继承所拥有的定义具有相同接口的对象族的能力也 是很重要的(通常可以从抽象类来继承) 。为什么?因为多态依赖于这种能力。 当继承被恰当使用时,所有从抽象类导出的类将共享该抽象类的接口。这意味着子类仅 仅添加或重定义操作,而没有隐藏父类的操作。这时,所有 的子类都能响应抽象类接口中的 请求,从而子类的类型都是抽象类的子类型。 只根据抽象类中定义的接口来操纵对象有以下两个好处: 1) 客户无须知道他们使用对象的特定类型,只须对象有客户所期望的接口。 2) 客户无须知道他们使用的对象是用什么类来实现的,他们只须知道定义接口的抽象类。 这将极大地减少子系统实现之间的相互依赖关系,也产生了可复用的面向对象设计的如 下原则: 针对接口编程,而不是针对实现编程。 不将变量声明为某个特定的具体类的实例对象,而是让它遵从抽象类所定义的接口。这 是本书设计模式的一个常见主题。 当你不得不在系统的某个地方实例化具体的类 ( 即指定一个特定的实现 ) 时,创建型模式 第1章 引 言 1 3 下载 (Abstract Factory(3.1) ,B u i l d e r ( 3 . 2 ) ,Factory Method(3.3) ,P r o t o t y p e ( 3 . 4 )和S i n g l e t o n ( 3 . 5 ) )可 以帮你。通过抽象对象的创建过程,这些模式提供不同方式以在实例化时建立接口和实现的 透明连接。创建型模式确保你的系统是采用针对接口的方式书写的,而不是针对实现而书写 的。 1.6.5 运用复用机制 理解对象、接口、类和继承之类的概念对大多数人来说并不难,问题的关键在于如何运 用它们写出灵活的、可复用的软件。设计模式将告诉你怎样去做。 1. 继承和组合的比较 面向对象系统中功能复用的两种最常用技术是类继承和对象组合(object composition) 。正 如我们已解释过的,类继承允许你根据其他类的实现来定义一个类的实现。这种通过生成子 类的复用通常被称为 白箱复用(white-box reuse) 。术语“白箱”是相对可视性而言:在继承方 式中,父类的内部细节对子类可见。 对象组合是类继承之外的另一种复用选择。新的更复杂的功能可以通过组装或组合对象 来获得。对象组合要求被 组合 的对象具有良好定义的接口。这种复用风格被称为黑箱复用 (black-box reuse) ,因为对象的内部细节是不可见的。对象只以“黑箱”的形式出现。 继承和组合各有优缺点。类继承是在编译时刻静态定义的,且可直接使用,因为程序设 计语言直接支持类继承。类继承可以较方便地改变被复用的实现。当一个子类重定义一些而 不是全部操作时,它也能影响它所继承的操作,只要在这些操作中调用了被重定义的操作。 但是类继承也有一些不足之处。首先,因为继承在编译时刻就定义了,所以无法在运行 时刻改变从父类继承的实现。更糟的是,父类通常至少定义了部分子类的具体表示。因为继 承对子类揭示了其父类的实现细节,所以继承常被认为“破坏了封装性” [ S n y 8 6 ] 。子类中的 实现与它的父类有如此紧密的依赖关系,以至于父类实现中的任何变化必然会导致子类发生 变化。 当你需要复用子类时,实现上的依赖性就会产生一些问题。如果继承下来的实现不适合 解决新的问题,则父类必须重写或被其他更适合的类替换。这种依赖关系限制了灵活性并最 终限制了复用性。一个可用的解决方法就是只继承抽象类,因为抽象类通常提供较少的实现。 对象组合是通过获得对其他对象的引用而在运行时刻动态定义的。组合要求对象遵守彼 此的接口约定,进而要求更仔细地定义接口,而这些接口并不妨碍你将一个对象和其他对象 一起使用。这还会产生良好的结果:因为对象只能通过接口访问,所以我们并不破坏封装 性;只要类型一致,运行时刻还可以用一个对象来替代另一个对象;更进一步,因为对象的 实现是基于接口写的,所以实现上存在较少的依赖关系。 对象组合对系统设计还有另一个作用,即优先使用对象组合有助于你保持每个类被封装, 并被集中在单个任务上。这样类和类继承层次会保持较小规模,并且不太可能增长为不可控 制的庞然大物。另一方面,基于对象组合的设计会有更多的对象 (而有较少的类) ,且系统的行 为将依赖于对象间的关系而不是被定义在某个类中。 这导出了我们的面向对象设计的第二个原则: 优先使用对象组合,而不是类继承。 理想情况下,你不应为获得复用而去创建新的构件。你应该能够只使用对象组合技术, 1 4 设计模式 :可复用面向对象软件的基础 下载 通过组装已有的构件就能获得你需要的功能。但是事实很少如此,因为可用构件的集合实际 上并不足够丰富。使用继承的复用使得创建新的构件要比组装旧的构件来得容易。这样,继 承和对象组合常一起使用。 然而,我们的经验表明:设计者往往过度使用了继承这种复用技术。但依赖于对象组合 技术的设计却有更好的复用性 (或更简单) 。你将会看到设计模式中一再使用对象组合技术。 2. 委托 委托(d e l e g a t i o n)是一种组合方法,它使组合具有与继承同样的复用能力 [ L i e 8 6 , J Z 9 1 ]。在 委托方式下,有两个对象参与处理一个请求,接受请求的对象将操作委托给它的代理者 (d e l e g a t e)。这类似于子类将请求交给它的父类处理。使用继承时,被继承的操作总能引用接 受请求的对象,C + + 中通过t h i s成员变量,S m a l l t a l k 中则通过s e l f 。委托方式为了得到同样的 效果,接受请求的对象将自己传给被委托者(代理人),使被委托的操作可以引用接受请求的 对象。 举例来说,我们可以在窗口类中保存一个矩形类的实例变量来代理 矩形类的特定操作, 这样窗口类可以复用矩形类的操作,而不必像继承时那样定义成矩形类的子类。也就是说, 一个窗口拥有一个矩形,而不是一个窗口就是一个矩形。窗口现在必须显式的将请求转发给 它的矩形实例,而不是像以前它必须继承矩形的操作。 下面的图显示了窗口类将它的A r e a操作委托给一个矩形实例。 箭头线表示一个类对另一个类实例的引用关系。引用名是可选的,本例为“ r e c t a n g l e ”。 委托的主要优点在于它便于运行时刻组合对象操作以及改变这些操作的组合方式。假定 矩形对象和圆对象有相同的类型,我们只需简单的用圆对象替换矩形对象,则得到的窗口就 是圆形的。 委托与那些通过对象组合以取得软件灵活性的技术一样,具有如下不足之处:动态的、 高度参数化的软件比静态软件更难于理解。还有运行低效问题,不过从长远来看人的低效才 是更主要的。只有当委托使设计比较简单而不是更复杂时,它才是好的选择。要给出一个能 确切告诉你什么时候可以使用委托的规则是很困难的。因为委托可以得到的效率是与上下文 有关的,并且还依赖于你的经验。委托最适用于符合特定程式的情形,即标准模式的情形。 有一些模式使用了委托,如 S t a t e ( 5 . 8 ) 、S t r a t e g y ( 5 . 9 )和Vi s i t o r ( 5 . 11 ) 。在S t a t e模式中,一 个对象将请求委托给一个描述当前状态的 S t a t e对象来处理。在 S t r a t e g y模式中,一个对象将一 个特定的请求委托给一个描述请求执行策略的对象,一个对象只会有一个状态,但它对不同 的请求可以有许多策略。这两个模式的目的都是通过改变受托对象来改变委托对象的行为。 在Vi s i t o r 中,对象结构的每个元素上的操作总是被委托到 Vi s i t o r对象。 其他模式则没有这么多 地用到委托。M e d i a t o r ( 5 . 5 ) 引进了一个中介其他对象间通信的对 第1章 引 言 1 5 下载 象。有时,M e d i a t o r对象只是简单地将请求转发给其他对象;有时,它沿着指向自己的引用 来传递请求,使用真正意义的委托。 Chain of Responsibility(5.1)通过将请求沿着对象链传递 来处理请求,有时,这个请求本身带有一个接受请求对象的引用,这时该模式就使用了委托。 B

  “原创力文档”前称为“文档投稿赚钱网”,本网站为“文档C2C交易模式”,即用户上传的文档直接卖给(下载)用户,本站只是中间服务平台,本站所有文档下载所得的收益归上传人(含作者)所有【成交的100%(原创)】

本文链接:http://pebeducation.com/fanxiangfuyong/400.html