文章目录
定义设计模式
定义
定义
: 模式是在某个情境(context)下,针对某个问题的某种解决方案
下面我们来逐步了解定义中所提到的情境、问题、解决方案。
- 情境就是运用某个模式的情况,这应该是会不断出现的情况,很常见一般的情况。
- 问题是你想在某情境下要达到的目标,在这种情境下的约束。
- 解决方案就是你所追求的:一个通用的设计,用来解决约束,达到目标
接下来我们可以重新去定义这个设计模式
- 定义(详细):如果你发现自己处在某个情境下,面对着所欲达到的目标被一群约束影响着的问题,然而,你能够应用某个设计,克服这些约束并达到该目标,将你领向某个解决方案。
- Christopher Alexander的原话 :每一个模式描述了一个在我们周围不断重复发生的问题,以及该问题的解决方案的核心。这样,你就能一次又一次使用该方案而不必重复劳动。
举个简单的例子:
- 情境:我的自行车坏了
- 问题:我如何才能准时上班
- 解决方案:我可以坐公交去上班。
这样定义所需要的三部分我们全都有了,我们有一个问题,这个问题包括去上班的目标的,时间空间的约束,可能还有其他的影响因素;我们也具有情境,也就是自行车坏了,我们也有拥有一个解决方案,让我们解决时间和空间的约束。虽然这三部分我们都有,但这并不算是一个真正的模式,因为自行车不能每天都坏,情境缺乏一般性,不是应用于反复出现的问题。
除了上述情况之外,它在某些方面也不符合规定,,首先,别人想要在自己的特殊问题上采用这个方式可能并行不通,如果汽车坏了,坐公交去上班可能依旧会迟到,其次,它也违反了模式所应具备的一个重要而简单的特性:它没有一个名字!如果没有名字,一个模式无法变成开发人员之间共享的词汇。
幸运的是,模式并非只是被描述成简单的问题,情境和解决方案,我们有更好的方案能描述模式,并将它们收录进“模式类目”中。
Q&A
- Q: 稍微改变某个模式的以符合我的设计,这样可以吗?
- A:你当时可以改变模式。想设计原则一样,模式不是法律或者准则,模式时一种指导方针,你可以改变模式来符合你的需要。我们也说过,真实世界的许多实例,都不是完全条条框框地符合经典的设计模式。然而。当你在改变模式的时候,最好在文档中注明它与经典的设计模式的差异。这样一来,其他的开发人员就能够很快的认出你用的这个模式,并了解两者的差异。
- Q:我要从哪里取得模式类目?
- A:第一个:也就是最重要的设计类目是Gamma,Helm,Johnson,Vlissides(俗称四人帮又名GOF)所著的《设计模式:可复用面向对象软件的基础》(英文名:DesignPatterns:Elements of Reusable Object-Oriented Software).这个类目列出了23个基本模式。 第二个:另外许多将焦点放到不同领域(例如:企业软件,并发系统、业务系统)的模式类目,比如WEB后端对应也有许多相应的设计模式。DAO,Servlet等等,还得学啊,问题很大,居然词穷!- -!才刚刚开始呢。
模式类目
模式类目是一种更好的描述模式的方式。
- 它描述了某个模式的意图、模式类别、别名、动机、适用性、结构、参与者、协作、效果、实现、代码示例、已知应用、相关模式。
- 意图:简短地描述该模式的作用。你也可以把它看作是模式的定义
- 模式类别:描述模式属于哪种类别,当下主流的模式模式分类是三种:创建型模式,行为型模式,结构型模式。
- 别名:模式的其它名称
- 动机:给出了问题以及如果解决问题的具体场景
- 适用性:描述模式可以被运行的场合(偏概括)例如:Decorator模式可以在不影响其它对象的情况下,以动态、透明的方式给单个对象添加职责行为。
- 结构:用UML图去描述模式运作类与类之间的关系
- 参与者:描述在此设计中所涉及到的类和对象在模式中的责任和角色。
- 协作:告诉我们,参与者如何在这个模式中协作
- 效果:描述采用这个模式之后产生的效果:优点和缺点
- 实现:提供了你在实现该模式时需要使用的技巧,以及你应该需要注意的点
- 代码示例:提供代码的片段,可能对你的实现有所帮助。
- 已知应用:描述已经在真实系统中使用的模式的例子
- 相关模式:描述了这个模式与其它模式的关系,与其它模式的相同点,不同点,便于让你们区别模式,更加深入地理解模式。
模式分类
随着发掘的设计模式数目增加,越来越有必要将模式进行分类。好将它们组织起来,以简化我们寻找模式的过程,并让同一群组内的模式好进行互相比较,更加方便理解。
模式的分类方式有很多种,最广为人知的分类方式有两种:
- 第一种是根据模式的目标目的分成三个不同类别:
- 创建型模式:创建型模式涉及到对象实例化,这类模式都提供了方法,将客户从所需要的实例化的对象中解耦
- 行为型模式:行为型模式涉及到类和对象如何交互和分配职责
- 结构型模式:结构性模式可以让你把类或对象组合到更大的结构中
- 第二种是根据模式的范围分,指定模式主要用于类还是用于对象
- 类模式: 类模式描述类之间的关系如果通过继承定义。类模式的关系是在编译时建立的
- 对象模式:对象模式描述对象之间的关系,而且主要是利用组合定义。对象模式的关系通常在运行时建立,而且更加动态,更有弹性。
设计模式空间
分类标准 | 具体类别(按范围) | 按目的 | 按目的 | 按目的 |
---|---|---|---|---|
具体类别(按目的) | 创建型 | 行为型 | 结构型 | |
按范围 | 类 | Factory Method(工厂方法) | Interpreter(解释器模式),Template Method(模板方法) | Adapter(类适配器 Java中无法实现) |
按范围 | 对象 | Abstract Factory(抽象工厂),Builder(生成器),Prototype(原型),Singleton(单例) | Chain of Responsibility(责任链),Command(命令),Iterator(迭代器),Mediator(中介者),Memento(备忘录),Observer(观察者),State(状态),Stategy(策略),Visitor(访问者) | Adapter(对象适配器),Bridge(桥接),Composite(组合),Decorator(装饰器),Facade(外观),Flyweight(享元),Proxy(代理) |
关于分类的意义,举个例子,就拿汽车来讲吧:汽车有许多不同的款式,我们一般把汽车分成几类,例如:经济车、跑车、旅行车、卡车和豪华轿车,一旦你有了分类,你就可以很方便这么说:“如果你想从硅谷开车到洛杉矶,那么跑车将会是最好的选择。”或者“因为石油的市场状况日益恶化,应该购买经济车,比较省油。”
有了分类,能够便于思考,先找出大类,再从大类中找小类,就好比数据库一样,这样可以提高检索速度,提高效率。
用模式去思考
下面是一份快速指南,可以帮助你开始“用模式思考”,所谓”用模式去思考“,意识是说,能够看着设计,体会在什么地方能自然适用,在什么地方则不会。
KISS原则(Keep It Simple and Stupid)
首先,当你设计时。尽可能地用最简单的方式解决问题,你的目标应该是简单,而不是“如何在这个问题中应用模式”,千万不要认为,如果没有使用模式解决某个问题,就不是经验丰富的开发人员。如果你能够保持简单的设计,那么你将会得到其他开发人员的欣赏和尊敬。正确的说法是,为了让你的设计简单而又弹性,有时候使用模式时最好的方法。
设计模式并非万金油。
如你所知道的,模式时解决一再发生的问题的通用方案,模式已经被许多开发人员实际测试过。所以,当你需要某个模式的时候,可以放心地使用它,毕竟你知道这个模式已经身经百战。
然而,模式并非万灵丹,你不能把模式插入,编译,然后就早早地去吃午餐,药使用模式,你需要考虑到模式对你的设计其他部分所造成的后果(有优点也有缺点)。
何时使用模式?
啊……这是最重要的问题,什么时候使用模式?当你在设计的时候,如果确定在你的设计中可以利用某个模式解决某个问题,那么就使用模式!如果有更简单的方案,那么在决定使用模式之前应该先考虑这个方案。
如何知道何时适合一个模式,这就需要经验和知识。一旦你确定一个简单的解决方案无法满足你的需求,应该考虑这个问题以及相关约束——这可以帮你将问题对应到一个模式中,如果你对于模式有很深的认知,就可能知道什么模式适合这样的情况。否则,就花些时间调查一下可能会解决这个问题的模式,多去查阅一下模式类目,模式类目中的意图和应用部分会特别有用。一旦找到了一个看起来适合的模式,要先确定你是否能够接受这个模式所带来的后果,已经对设计其他部分的影响,如果一切看起来都很好。就用它吧。
有一种情况,即使有更简单的解决方案,你仍然想要使用模式,这种情况就是你预期系统在未来会发生改变。正如我们所见过的,找出你的设计中会改变的区域,通常这是需要模式的迹象,但是务必要确认一件事,加入模式时要应对可能发生的实际改变,而不是假想的改变,就是说比如你设计一个糖果机,可能和糖果机很受欢迎,需要多个出口,或者有新品要添加进入糖果机,这就是可能发生的实际改变,比如让糖果机可以玩LOL,这TM就是假想的改变!
并非只有在设计时才考虑引进模式,重构的时候也要这么做。
并非只有在设计时才考虑引进模式,重构的时候也要这么做
重构就是通过改变你的代码来改进它的组织方式的过程。目标是要改变其结构,而不是其行为。这是一个很好的时机,可以重新检查你的设计来看看是能够利用模式让它有用更好的结构。比方说,代码内如果充满了条件语句,这可能以为这需要使用状态模式,,或者意味着,应该利用工厂模式将这些具体的依赖消除掉。许多书都介绍如果利用模式进行重构,而随着技艺的增长,你需要更多的狩猎这个领域。
拿掉你所不需要的,不要害怕将一个设计模式从你的设计中删除
还没有人谈到何时应该将某个模式删除。那么何时应该删除某个模式呢
当你的系统变得非常复杂,而且并不需要预留任何弹性的时候,就不要使用模式。换句话说,也就是当一个简单的解决防范比使用模式更恰当的时候。
如果现在不需要,就别做
设计模式威力强大,你很容易就可以在当前设计中看到模式的各种应用方式。开发人员天生就热爱创建漂亮的架构以应对任何方向的改变。
要抗拒这种诱惑啊!如果你今天在设计中有实际的需要去支持改变,就方式采用模式处理这个改变吧!然而,如果说理由只是假象的,就不要添加这个模式,因为这只会将你的系统越搞越复杂,而且很可能你永远不会需要它。
模式就是工具,是牛刀,应用"模式"要恰当!
模式是一种工具,只要在需要的时候才是用这种工具,一开始先遵循设计原则,建立最简单的代码以完成工作,在这个过程中,你看到有需要模式的地方,就使用模式。“使用模式/应用模式”绝对不是你开始设计该有的目标。应该让模式在你的设计过程中自然而然地出现。
模式可能带来复杂性,如果没有必要,我们绝不需要这样的复杂性。就像你已经知道的,模式时一种被证实过的设计经验,可以避免某些常见的错误,模式也是一种共享的词汇,能够让我们和其他开发人员提高我们沟通我们的设计的效率。共享词汇也是一种设计模式最大优点之一。
过度使用设计模式可能导致代码被过度工程化,应该总是用最简单的解决防范完成工作,并在真正需要模式的地方才使用它。应用模式要恰当!
使用共享词汇的五种场合
共享词汇能够节省大量的沟通时间,那么共享词汇使用在那些场合呢?
- 1. 在设计会议中:
当你和你的团队在会议中讨论软件设计时,使用设计模式可以帮助你们在“设计中讨论”久一点,从设计模式到面向对象原则的视角讨论设计,可以避免你们的团队很快地陷入实现的细节,也可以避免发生很多误解。
- 2.和其他开发人员
当你和其他开发人员讨论的时候,可以使用模式。这可以帮助其他开发人员学习新模式,并建立一个社群。和别人分享你所学会的东西是很有成就感的一件事
- 3.在架构代码中
当你在编写架构文档的时候,使用模式将会缩减文档的额篇幅,并且让读者更清楚你的设计。
- 4.在代码注释和命名习惯上
当你编写代码的时候,应在注意中清楚地注明你所使用的模式。在选择类和方法的名称是,应尽可能显示出隐藏在下面的模式。其他开发的开发人员在阅读你的代码时会感激你,因为你让他们很快地了解你的实现。
- 5.将志同道合的开发人员集合在一起
分享你的知识。许多开发人员都听说过模式,但并不真正了解什么是模式。你可以自愿地为他们讲一堂模式介绍课或者成立一个读书会。。。。。。。。
推荐文献
《设计模式:可复用面向对象软件的基础》
《The Timeless Way of Building》
《A Pattern Language》
引用文献
《HeadFirst设计模式》
《设计模式:可复用面向对象软件的基础》