设计模式概述
内容
- 模式是什么
- 软件模式的由来
- 软件模式的构成
- 设计模式是什么
- 设计模式用途分类,常用模式一览
- 设计模式的价值
- 如何学习设计模式
模式是什么
美国Christopher Alexander博士及其研究团队用了约20年的时间,对住宅和周边环境进行了大量的调查研究和资料收集工作,发现人们对舒适住宅和城市环境存在一些共同的认同规律,Christopher Alexander在著作A Pattern Language: Towns, Buildings, Construction中把这些认同规律归纳为253个模式,对每一个模式(Pattern)都从Context(前提条件)、Theme或Problem(目标问题)、 Solution(解决方案)三个方面进行了描述,并给出了从用户需求分析到建筑环境结构设计直至经典实例的过程模型。
在Christopher Alexander的另一部经典著作《建筑的永恒之道》中,他给出了关于模式的定义:
每个模式都描述了一个在我们的环境中不断出现的问题,然后描述了该问题的解决方案的核心,通过这种方式,我们可以无数次地重用那些已有的成功的解决方案,无须再重复相同的工作。
这个定义可以简单地用一句话表示:
模式是在特定环境下人们解决某类重复出现问题的一套成功或有效的解决方案。
A pattern is a successful or efficient solution to a recurring problem within a context.
软件模式的由来(23种)
1990年,软件工程界开始关注Christopher Alexander等在这一住宅、公共建筑与城市规划领域的重大突破。最早将模式的思想引入软件工程方法学的是1991-1992年以“四人组”自称的四位著名软件工程学者。
Gang of Four,简称GoF,分别是Erich Gamma, Richard Helm, Ralph Johnson和John Vlissides。
书名:Design Patterns: Elements of Reusable Object-Oriented Softwarec - 设计模式:可复用面向对象软件的基础
他们在1994年归纳发表了23种在软件开发中使用频率较高的设计模式,旨在用模式来统一沟通面向对象方法在分析、设计和实现间的鸿沟。
GoF将模式的概念引入软件工程领域,这标志着软件模式的诞生。软件模式是将模式的一般概念应用于软件开发领域,即软件开发的总体指导思路或参照样板。软件模式并非仅限于设计模式,还包括架构模式、分析模式和过程模式等,实际上,在软件开发生命周期的每一个阶段都存在着一些被认同的模式。
软件模式的构成
软件模式是在软件开发中某些可重现问题的一些有效解决方法,软件模式的基础结构主要由四部分构成,包括问题描述(待解决的问题是什么)、前提条件(在何种环境或约束条件下使用)、解法(如何解决)和效果(有哪些优缺点)。
设计模式是什么
在软件模式中,设计模式是研究最为深入的分支,设计模式用于在特定的条件下为一些重复出现的软件设计问题提供合理的、有效的解决方案,它融合了众多专家的设计经验,已经在成千上万的软件中得以应用。 1995年, GoF将收集和整理好的23种设计模式汇编成Design Patterns: Elements of Reusable Object-Oriented Software(《设计模式:可复用面向对象软件的基础》)一书,该书的出版也标志着设计模式正式成为面向对象软件工程的一个重要研究分支。
设计模式的一般定义如下:
设计模式(Design Pattern)是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结,使用设计模式是为了可重用代码、让代码更容易被他人理解并且保证代码可靠性。
设计模式的要素
设计模式一般包含模式名称、问题、目的、解决方案、效果等组成要素,其中关键要素是模式名称、问题、解决方案和效果。
- 模式名称(Pattern Name)通过一两个词来描述模式的问题、解决方案和效果,以便更好地理解模式并方便开发人员之间的交流,绝大多数模式都是根据其功能或模式结构来命名的(GoF设计模式中没有一个模式用人名命名)
- 问题(Problem)描述了应该在何时使用模式,它包含了设计中存在的问题以及问题存在的原因
- 解决方案(Solution)描述了一个设计模式的组成成分,以及这些组成成分之间的相互关系,各自的职责和协作方式,通常解决方案通过UML类图和核心代码来进行描述
- 效果(Consequences)描述了模式的优缺点以及在使用模式时应权衡的问题。
设计模式的用途分类
虽然GoF设计模式只有23个,但是它们各具特色,每个模式都为某一个可重复的设计问题提供了一套解决方案。
根据它们的用途,设计模式可分为创建型(Creational),结构型(Structural)和行为型(Behavioral)三种。
- 创建型模式主要用于描述如何创建对象;
- 结构型模式主要用于描述如何实现类或对象的组合;
- 行为型模式主要用于描述类或对象怎样交互以及怎样分配职责。
在GoF 23种设计模式中包含5种创建型设计模式、7种结构型设计模式和11种行为型设计模式。
此外,根据某个模式主要是用于处理类之间的关系还是对象之间的关系,设计模式还可以分为类模式和对象模式。
我们经常将两种分类方式结合使用,如单例模式是对象创建型模式,模板方法模式是类行为型模式。
常用设计模式一览表
值得一提的是,有一个设计模式虽然不属于GoF 23种设计模式,但一般在介绍设计模式时都会对它进行说明,它就是简单工厂模式,也许是太“简单”了,GoF并没有把它写到那本经典著作中,不过现在大部分的设计模式书籍都会对它进行专门的介绍。
(以下难度、频率统计结果来自刘伟)
类型 | 模式名称 | 学习难度 | 使用频率 |
---|---|---|---|
创建型模式 Creational | 单例模式 Singleton | ★☆☆☆☆ | ★★★★☆ |
简单工厂模式 | ★★☆☆☆ | ★★★☆☆ | |
工厂方法模式 Factory Method | ★★☆☆☆ | ★★★★★ | |
抽象工厂模式 Abstract Factory | ★★★★☆ | ★★★★★ | |
原型模式 Prototype | ★★★☆☆ | ★★★☆☆ | |
建造者模式 Builder | ★★★★☆ | ★★☆☆☆ | |
结构型模式 Structural | 适配器模式 Adapter | ★★☆☆☆ | ★★★★☆ |
桥接模式 Bridge | ★★★☆☆ | ★★★☆☆ | |
组合模式 Composite | ★★★☆☆ | ★★★★☆ | |
装饰模式 Decorator | ★★★☆☆ | ★★★☆☆ | |
外观模式 Facade | ★☆☆☆☆ | ★★★★★ | |
享元模式 Flyweight | ★★★★☆ | ★☆☆☆☆ | |
代理模式 Proxy | ★★★☆☆ | ★★★★☆ | |
行为型模式 Behavioral | 职责链模式 Chain of Responsibility | ★★★☆☆ | ★★☆☆☆ |
命令模式 Command | ★★★☆☆ | ★★★★☆ | |
解释器模式 Interpreter | ★★★★★ | ★☆☆☆☆ | |
迭代器模式 Iterator | ★★★☆☆ | ★★★★★ | |
中介者模式 Mediator | ★★★☆☆ | ★★☆☆☆ | |
备忘录模式 Memento | ★★☆☆☆ | ★★☆☆☆ | |
观察者模式 Observer | ★★★☆☆ | ★★★★★ | |
状态模式 State | ★★★☆☆ | ★★★☆☆ | |
策略模式 Strategy | ★☆☆☆☆ | ★★★★☆ | |
模板方法模式 Template Method | ★★☆☆☆ | ★★★☆☆ | |
访问者模式 Visitor | ★★★★☆ | ★☆☆☆☆ |
1句话描述23个设计模式
结构型
-
适配器模式(Adapter):将一个类的接口转换成客户希望的另一个接口。
- 例子:电源适配器,将两孔插头适配成三孔插头。
-
桥接模式(Bridge):将抽象部分与它的实现部分分离,使它们可以独立变化。
- 例子:遥控器(抽象部分)和不同类型的电视机(实现部分)。
- 苹果系统中OC和C语言之间的桥梁。
-
组合模式(Composite):将对象组合成树形结构以表示“部分-整体”的层次结构,使得用户对单个对象和组合对象的使用具有一致性。
- 例子:文件夹和文件的结构,一个文件夹可以包含文件或子文件夹。
-
装饰模式(Decorator):动态地给对象添加一些额外的职责。
- 例子:给圣诞树添加装饰品,每个装饰品增加新的特性。
-
外观模式(Facade):为子系统中的一组接口提供一个一致的界面,使子系统更容易使用。
- 例子:餐厅服务员,统一点菜、送菜和结账的接口。
-
享元模式(Flyweight,也叫轻量对象模式):通过共享大量细粒度对象来节省内存。
- 例子:围棋棋子,黑白棋子共享一个对象,节省内存。
-
代理模式(Proxy):为其他对象提供一种代理,以控制对这个对象的访问。
- 例子:明星的经纪人,代理处理事务和安排活动。
行为型
-
责任链模式(Chain of Responsibility):将请求消息沿着处理者链传递,直到有处理者处理它。
- 例子:公司请假审批流程,依次由主管、经理、总监审批。
-
命令模式(Command):将请求封装成对象,使不同的请求、队列或日志参数化。
- 例子:遥控器上的按钮,每个按钮封装一个命令。
-
解释器模式(Interpreter):给定一个语言,定义它的文法表示,并定义一个解释器来处理这些表示。
- 例子:正则表达式解析器,解释和处理正则表达式。
- 3D软件中通过脚本或命令按钮控制界面,或控制物体运动。
-
迭代器模式(Iterator):提供一种方法顺序访问一个聚合对象中的各个元素,而不暴露其内部表示。
- 例子:图书馆的书架,使用迭代器遍历书籍。
- STL中容器和算法之间的桥梁。
-
中介者模式(Mediator):用一个中介对象来封装一系列对象的交互。
- 例子:机场的塔台,调度和管理飞机的起降。
- 游戏引擎中用的居多。
-
备忘录模式(Memento):在不破坏封装的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。
- 例子:电脑的系统还原点,记录系统状态以便将来恢复。
- Word编辑过程中的undo、redo。
-
观察者模式(Observer):定义对象间的一种一对多的依赖关系,使得每当一个对象改变状态,则所有依赖于它的对象都会得到通知并被自动更新。
- 例子:订阅报纸,当报纸有新内容时,通知所有订阅者。
-
状态模式(State):允许对象在内部状态改变时改变它的行为。
- 例子:电梯的状态,不同状态(上下楼、开关门)下电梯行为不同。
-
策略模式(Strategy):定义一系列算法,将每个算法封装起来,并使它们可以互换。
- 例子:旅游出行策略,根据情况选择不同的出行方式(开车、坐公交、骑自行车)。
- 比如HDC,不同的设备对应不同的DC。
-
模板方法模式(Template Method):定义一个操作中的算法的骨架,而将一些步骤延迟到子类中,使得子类可以不改变算法的结构即可重定义该算法的某些步骤。
- 例子:制作咖啡的步骤,具体的咖啡制作细节由不同种类的咖啡决定。
- Windows_面向对象程序设计中建立的Window框架就是模板方法模式。
-
访问者模式(Visitor):表示一个作用于某对象结构中的各元素的操作,使得可以在不改变各元素类的前提下定义作用于这些元素的新操作。
- 例子:博物馆导览员,不同导览员为游客讲解不同展品的信息。
创建型
-
单例模式(Singleton):确保一个类只有一个实例,并提供全局访问点。
- 例子:总统办公室(全国只有一个总统)。
-
工厂方法模式(Factory Method):定义一个创建对象的接口,但让子类决定实例化哪个类。
- 例子:披萨店,根据订单制作不同类型的披萨。
-
抽象工厂模式(Abstract Factory):提供一个接口,用于创建相关或依赖对象的家族,而无需指定具体类。
- 例子:家具工厂,可以创建一整套风格一致的家具(如现代风格或古典风格)。
-
建造者模式(Builder):将一个复杂对象的构建过程拆解,与其表示分离,使同样的构建过程可以创建不同的表示。
- 例子:建筑工人,按照设计图纸建造不同的房屋。
-
原型模式(Prototype):通过复制现有对象来创建新对象。
- 例子:细胞分裂,通过复制自身产生新细胞。
设计模式的价值
大部分设计模式都兼顾了系统的可重用性和可扩展性,这使得我们可以更好地重用一些已有的设计方案、功能模块甚至一个完整的软件系统,避免我们经常做一些重复的设计、编写一些重复的代码。
此外,随着软件规模日益增大,系统的可维护性和可扩展性也越来越重要,许多设计模式将有助于提高系统的灵活性和可扩展性,让我们在不修改或者少修改现有系统的基础上增加、删除或者替换功能模块。
如何学习设计模式
- 在学习每一个设计模式时至少应该掌握如下几点:当你能够回答所有问题时,恭喜你,你了解一个设计模式了,至于掌握它,那就在开发中去使用吧,用多了你自然就掌握了。
- 这个设计模式的意图是什么,它要解决一个什么问题,什么时候可以使用它;
- 它是如何解决的,掌握它的结构图,记住它的关键代码;
- 能够想到至少两个它的应用实例,一个生活中的,一个软件中的;
- 这个模式的优缺点是什么,在使用时要注意什么。
- “如果想体验一下运用模式的感觉,那么最好的方法就是运用它们。”正如在本章最开始所说的,设计模式是“内功心法”,它还是要与“实战招式”相结合才能够相得益彰。学习设计模式的目的在于应用,如果不懂如何使用一个设计模式,而只是学过,能够说出它的用途,绘制它的结构,充其量也只能说你了解这个模式,严格一点说:不会在开发中灵活运用一个模式基本上等于没学。所以一定要做到:少说多做。
- 不要滥用模式,不要试图在一个系统中用上所有的模式。每个模式都有自己的适用场景,不能为了使用模式而使用模式。
- 如果将设计模式比喻成“三十六计”,那么每一个模式都是一种计策,它为解决某一类问题而诞生,不管这个设计模式的难度如何,使用频率高不高,都应该好好学学,多学一个模式也就意味着你多了“一计”,说不定什么时候就用上了。
- 设计模式的“上乘”境界:“手中无模式,心中有模式”。模式使用的最高境界是你已经不知道具体某个设计模式的定义和结构了,但你会灵活自如地选择一种设计方案(其实就是某个设计模式)来解决某个问题,设计模式已经成为你开发技能的一部分,能够手到擒来,“内功”与“招式”已浑然一体,要达到这个境界并不是看完某本书或者开发一两个项目就能够实现的,它需要不断沉淀与积累,所以,对模式的学习不要急于求成。
- GoF已故成员、软件工程大师之一John Vlissides的著作《设计模式沉思录》(Pattern Hatching Design Patterns Applied):模式从不保证任何东西,它不能保证你一定能够做出可复用的软件,提高你的生产率,更不能保证世界和平;模式并不能替代人来完成软件系统的创造,它们只不过会给那些缺乏经验但却具备才能和创造力的人带来希望。