设计模式
模式
什么是模式?
从宿舍或实验室出发,去上课或用餐,我们采用过不同方式去完成这个行为。通过回忆这些方式,通过对比可以发现,当我们刚刚来到一所学校,由于对校园的环境不熟悉,有时候会走很长的路到达目的地;一段时间之后,我们对这所学校的环境的越来越熟悉,我们可以找到一条合适的路径;后来,我们又利用自行车或其它交通工具进一步节省我们在路途上花耗的时间。从刚来到这所学校到我们骑着一辆自行车在校园里溜达可能间隔3周时间。假若某一天你身边来了一位新生,他和你当初一样步行并且经常走冤枉路,你可能会告诉他哪条路比较近,骑自行车和使用其他交通工具会比较省时,这位新生可能会采纳你的建议。
挑选较近的路线、使用交通工具来节省时间这对大多数人是可以接受并采纳的方案,并且该方案在不同的人身上不断重复使用,他们更不必花耗几周的时间来考虑这个问题。针对该问题的解决方案可以称为一种模式。那么,所谓的“模式”也就是经验。
模式的特征
每个模式都是一个由3部分组成的规则,它表达的是某一环境、一个问题以及解决问题的方案之间的关系。作为世界中的元素,每一个模式都是这三者之间的关系:
1.某一环境
2.此环境中反复出现的某个因素系统
3.使这些因素能够自我协调的某种空间配置
模式表明如何反复使用这个空间配置来解决给定的因素系统,只要这个空间配置在该环境中适用,并且可预见到好的结果。因此,我们可以总结到:
模式 = 问题背景 + 问题 + 解决方案.
简而言之,模式是存在于世界中的事物,同时也是告诉我们如何创造这个事物,以及何时必须创造它的规则。它既是过程,又是事物;既描述了有活力的事物,又描述了产生事物的过程。模式并非一种详细的描述,我们可以把它当作累积的智慧和经验的描述,是对一般问题的一个经过多次提炼的解决方案。所以,在软件的整个开发过程中都存在着可使用的模式,比如分析模式(荐《分析模式——可复用的对象模型》Martin Fowler著)&设计模式。使用模式有助于我们利用熟练的软件工程师的集体经验来构建软件;模式捕捉软件开发中现存的、充分考验的经验,再用于促进好的设计实践。
通常,一个模式由以下四个方面进行组成,分别是:
1.模式名称:模式的一个有意义的的指代,通常用来描述一个设计问题、它的解法和后果,由一到两个词组成。
2.问题域的描述:解释什么时候模式可以应用、解释问题及其背景。
3.针对问题的解决方案的描述:描述设计的基本要素,它们的关系、各自的任务以及相互之间的合作。
4.结果的陈述:描述应用设计模式后的结果和权衡;比较与其他设计方法的异同,得到应用设计模式的代价和优点。
理解和讨论模式,就必须以适当形式描述模式。好的描述有助于我们立即抓住模式的本质,即模式关心的问题是什么,以及提出解决方案是什么。目前最常用的对模式的描述方式是Erich Gamma博士等人采用的固定模式。
- 模式名称和分类:模式名称和一个简短的摘要。
- 目的:即设计模式的用处、基本原理和目的、它针对的是什么特殊的设计问题。
- 别名:同一个模式可能会有不同的命名。
- 动机:描述一个设计问题的方案,以及模式中类和对象的结构如何解决这个问题。
- 应用:在什么情况下可以应用本设计模式。
- 结构:用对象模型技术对本模式进行表示。
- 成分:组成本设计模式的类和对象及它们的职责。
- 合作:成分间如何合作实现他们的任务。
- 后果:该模式如何支持它的对象;如何在使用本模式时进行权衡。
- 实现:在实现本模式的过程中,要注意哪些缺陷、线索或者技术;是否与编程语言有关。
- 例程代码:说明如何用C++或其他语言来实现该模块的代码段。
- 已知的应用:现实系统中使用该模式的实例。
- 相关模式:与本模式相关的其他模式,它们之间的区别,以及本模式是否要和其他模式共同使用。
设计模式
对于设计模式,可以从不同的层面进行讨论,如面向对象设计层面和软件的体系结构层面。首先介绍一下OOA&D
OOA&D
面向对象分析
面相对象分析阶段主要关注的是研究问题域和用户需求,运用面向对象的观点发现问题域中与系统责任有关的对象,以及对象的特征和相互关系。目标是建立一个直接映射问题域,符合用户需求的OOA模型。
面向对象设计
面向对象设计阶段是在OOA模型基础上,针对选定的实现平台进行系统设计,按照实现的要求进行具体的设计,目标是产生一个能够在选定的软硬件平台上实现的OOD模型。
MDA下的OOA&D
- OOA模型:抽象层次较高,忽略了与实现有关的因素。
- OOD模型:抽象层次较低,包含了与实现平台有关的细节。
MDA即模型驱动的体系结构,MD是指用模型来对系统的理解、设计、构造、部署、操作、维护和更新进行指导。

图 1-1
将MDA的观点运用在OOA&OOD上,那么OOA模型只针对问题域和系统责任,不涉及实现条件,因此可得到一个平台无关的OOA模型;OOD模型是在OOA模型基础上针对特定实现条件进行设计转换成一个平台专用的OOD模型。因此可以根据OOA模型在不同的平台上进行设计产生多个版本的OOD模型,所以OOA模型是可以复用的。
编程方法中的重点主要是正确有效地使用特定的语言机制,而设计方法的重点是正确有效地构造出复杂系统的结构。面向对象分析的重点在于构建真实世界的模型,利用面向对象的观点看世界,从问题域中寻找类和对象对需求进行分析。
面向对象设计模式
在20世纪90年代初,由Gamma、Helm、Johnson和Vlissides合著的《设计模式:可复用面向对象软件的基础》这部书对设计模式影响深远,为了褒奖他们的重要工作,大家给这四位作者一个昵称—GoF,即“四人组”。GoF在他们的书中从面相对象设计的角度根据面向对象的机制分析类或对象之间的协作关系编录了23个设计模式。这23个设计模式可根据模式的目的分为三类,分别为创建型、结构性和行为性。下面,我将具体介绍一个结构性模式—Bridge 模式。
Bridge 模式
图 1-2
|
意图 |
将一组实现与另一组使用它们的对象分离. |
|
问题 |
一个抽象类的派生类必须使用多个实现,但不能出现类数量爆炸性增长。 |
|
解决方案 |
为所有实现定义一个接口,供抽象类的所有派生类使用。 |
|
参与者与协作者 |
Abstraction为要实现的对象定义接口,Implementor为具体的实现类定义接口。Abstraction的派生类使用Implementor的派生类,却无需知道自己具体使用哪一个ConcreteImplementor。 |
|
效果 |
实现与使用实现的对象解耦,提供了可扩展性,客户对象无需操心实现问题。 |
|
实现 |
|
[例] 有一家面馆,面馆里有两位厨师李师傅和康师傅,李师傅擅长做拌面,康师傅擅长做汤面;每一份面都可以添加一种配菜,分别有番茄鸡蛋、榨菜肉丝和红烧牛肉;每一位顾客都可以选择一种面再添加一道配菜。
对于这个问题,我们可以将桥接模式进行复用。
图 1-3
在这里为什么要使用桥接模式?对这个问题分析可以发现,面馆的厨师是可变的,可能某一天面馆里又来了一位做刀削面的王师傅或者康师傅跳了槽创业销售方便面这都是有可能的;面馆为了吸引顾客可能会增加新的配菜。假设,我们是在仅对面进行抽象,将番茄鸡蛋汤面、番茄鸡蛋拌面、榨菜肉丝汤面等作为面的派生类,此时每增加一名厨师就会产生3个的类,如果配菜有10种,就会增加10个新类,类数量增长剧烈。这符合桥接模式对问题的描述。使用桥接模式后,无论是增加厨师还是配菜都不会附带新的类产生。
桥接模式深入分析
桥接模式为什么可以起到这样的作用?最直接的原因是桥接模式使用接口将变化进行了分离,使变化分解在在两个维度里不再表现在一个维度里。更深层的原因是,该模式准确地寻找到了类之间的稳定结构,将变化进行了分离;要考虑怎样在不重新设计的情况下进行改变——发现变化将其封装,这也是设计模式的精髓之处。
此外,我们通过该案例还应该认识到我们对面向对象的认识存在误区。什么是对象?传统看法认为对象是具有方法的数据集;这只是从实现的角度来认识对象。设计者对OOA模型的不清晰认识或者OOA模型对系统需求的错误反应会导致细节缺乏稳定性;所以从实现的角度来认识对象过早的关注细节,会使设计陷入不断的变动之中。从概念的角度设计的角度来对对象进行认识更有意义。概念视角关注类或者对象之间的关系,这些关系是相对宏观稳定的;从概念角度来看对象是具有责任的实体,对象的责任体现在它的行为上。对封装的传统看法认为是‘数据隐藏’,但封装的含义因该更加宽泛,它可以对实现细节隐藏,对派生类隐藏,对设计细节隐藏,实例化规则隐藏。
模式和软件体系结构
判断模式取得成功的一个重要准则是它们在多大程度上达到了软件工程的目标;模式必须支持复杂的、大规模系统的开发、维护以及演化,必须支持产业化软件的生产。
模式作为体系结构的构造块
- 对软件体系结构而言,模式的一个重要目标就是用已定义属性进行特定的软件体系结构的构造。也就是说某个具有符合软件体系结构某方面要求的模式可以用作这方面的构造,构建具有特定属性的软件体系结构。
- 软件体系结构的一般技术并没有针对特定问题的解决方案。比如面向对象分析与设计技术,它是一般技术并不针对特定问题(来自系统需求的问题域)。
- 模式使用特定的面向问题的技术来有效补充这些通用的与问题无关的体系结构技术。模式是针对系统需求问题域的解决方案总结而来的,所以他能够弥补软件体系结构技术这方面的缺陷。
构造异构体系结构
- 单个模式不能完成一个完整的软件体系结构的详细构造,它仅仅帮助设计师设计应用程序的某一方面。
- 为了有效使用模式,需要将它们组织成模式系统。模式系统统一描述模式,对它们分类,更重要的是,说明它们之间如何交互。帮助设计师找到正确的模式来解决一个问题或确认一个可选解决方案。
模式和方法
- 好的模式描述也包含它的实现指南,可将其看成是一种微方法,用来创建解决一个问题的方案。
- 通过提供方法的步骤来解决软件开发中的具体再现问题,这些微方法补充了通用的但与问题无关的分析和设计方法。
实现模式
- 目前的许多软件模式具有独特的面向对象风格。因此,人们往往认为,能够有效实现模式的唯一方式是使用面向对象编程语言,其实不然。
- 在设计层次,大多数模式只需要适当的编程语言的抽象机制,如模块或数据抽象。因此,可以用几乎所有的编程范例,并在所有的编程语言中来实现模式。

浙公网安备 33010602011771号