设计模式是软件设计领域常常出现的问题的典型解决方案,是可以定制的预构建蓝图,用于解决反复出现的设计问题。
- 不能直接把模式复制到程序中,不能像函数或者库那样使用。模式不是一段特定的代码,而是解决特定问题的通用概念。
模式常与算法混淆,因为它们都描述了一些常见问题的典型解决方案。算法常常定义一组达到某目标的清晰动作,而模式是解决方案的更高层描述。同样的模式应用到两个不同的程序时,代码可能是不同的。
目标:简要描述问题和方案。
- 动机:进一步描述问题和方案。
- 结构:展示构成模式各部分的类,以及它们的关系。
- 代码示例:流行语言的代码示例,让读者更容易掌握模式后的概念。
-
2 设计模式的历史
Christopher Alexander首先在《A Pattern Language: Towns,Buildings,Construction》一书中描述模式的概念。这本书描述了一种设计都市环境的语言。这个语言的单位是模式。模式描述窗户应该多高、建筑应该有多少层、临近的绿地应该多大等等。
Erich Gamma,John Vlissides,Ralph Johnson和Richard Helm受此启发,于1994年出版《Design Patterns:Elements of Reuseable Object-Oriented Software》(《设计模式:可服用面向对象软件的基础》),将设计模式的概念应用到编程中。这本书介绍了面向对象设计中解决各种问题的23种设计模式,很快成为畅销书。自此之后,设计模式在编程领域大行其道。
3 为什么要学习模式
很多程序员工作多年也不知道设计模式。实际上,这样的程序员可能会在不知道模式的情况下,实现某些模式。
设计模式是软件设计领域对常见问题的、经过尝试和测试的解决方案。就算你从来没有遇到过这些问题,知道这些模式也是有用的,因为这会让你学会如何使用面向对象设计的概念来解决各种问题。
设计模式定义了一种公共语言,让你更高效地与团队沟通。你可以说,“可以使用单体模式”,每个人都知道你的意思,没必要解释“单体”是什么。
4 对模式的苛求
弱编程语言的组装件:使用缺少必要抽象层级的语言或者技术,会增加对模式的需求。这种情况下,模式会成为组装件,给予语言更需要的超能力。比如说,在大多数现代编程语言中,策略模式可以用简单的匿名函数(lambda)实现。
- 解决方案效率低下:模式尝试系统化已经广泛使用的方法,但是很多人把这种统一当成教条,使用时不考虑项目的实际情况。
不正当的使用:有一把锤子的时候,任何东西看起来像是钉子。这个问题困扰着很多新手。学来设计模式之后,新手尝试在每个地方使用设计模式,但有的地方更适合简单的代码。
5 模式的分类
设计模式在复杂度、细节层次、可扩展性方面各不相同。用道路建设来打比方:要让十字路口更安全,可以仅仅安装交通灯,也可以建造带地下行人通道的多层立交桥。
最基本和底层的模式通常称作习惯用法(idioms),通常仅能用于单种编程语言。
- 大多数通用的、高层的模式称作架构模式(architectural patterns),可以在任何语言中实现,可用于设计整个应用的架构。
所有模式可以根据意图(intent)或者用途(purpose)分类:
- 创建模式(Creational patterns):提供对象创建机制,增加灵活性,并重用已有代码。
- 工厂方法(factory method)
- 抽象工厂(abstract factory)
- 建造者(builder)
- 原型(prototype)
- 单体(singleton)
- 结构模式(Structural patterns):解释如何装配对象和类到更大的结构中,同时保持结构灵活、高效。
- 适配器(adapter)
- 桥(bridge)
- 组合(composite)
- 装饰器(decorator)
- 外观模式(facade)
- 享元模式(flyweight)
- 代理模式(proxy)
- 行为模式(Behavioral patterns):关注对象间的高效通信和职责分配。
- 责任链(chain of responsibility)
- 命令模式(command)
- 迭代器(iterator)
- 中介模式(mediator)
- 备注模式(memento)
- 观察者模式(observer)
- 状态模式(state)
- 策略模式(strategy)
- 模板方法(template method)
- 访问者模式(visitor)