章节概述
设计模式是软件架构设计师的必修课,它是对被用来在特定场景下解决一般设计问题的类和互相通信的对象的描述。通俗地说,设计模式可以理解为对某一类问题的通用解决方案。设计模式来源于众多项目中的成功设计,经过抽象、总结、归纳而形成,其核心目的是提高系统的复用性、移植性和可维护性。GoF(Gang of Four)在《设计模式:可复用面向对象软件的基础》一书中首次系统性地提出了 23 种设计模式,并建立了软件设计模式的学术地位。
GoF 23 种模式按解决的问题分为三大类:创建型(解决对象创建问题,5种)、结构型(解决类与对象的组合结构问题,7种)、行为型(解决类与对象的交互与职责分配问题,11种)。每种设计模式在描述时至少包含四个要素:模式名称、问题、解决方案、效果。设计模式与软件架构风格在思想上是一致的,如消息总线架构与 Observer 模式神似,掌握设计模式对架构设计大有裨益。本章在考试中出题频率较高,需重点掌握模式分类与代表性模式的意图。
知识结构框架
- 10.1 设计模式概述 — 概念、组成(四要素)、GoF 23 种模式、其他设计模式(J2EE)、设计模式与软件架构、设计模式分类
- 10.2 设计模式及实现 — Abstract Factory(抽象工厂)、Singleton(单例)、Decorator(装饰)、Facade/Session Facade(外观)、Mediator(中介者)、Observer(观察者)、Intercepting Filter(筛选器)
- 10.3 设计模式总结 — 模式综合运用、避免滥用、重构时机
- 创建型设计模式(5种) — Factory Method、Abstract Factory、Builder、Prototype、Singleton
- 结构型设计模式(7种) — Adapter、Bridge、Composite、Decorator、Facade、Flyweight、Proxy
- 行为型设计模式(11种) — Interpreter、Template Method、Chain of Responsibility、Command、Iterator、Mediator、Memento、Observer、State、Strategy、Visitor
核心概念
单例 Singleton
保证一个类仅有一个实例,提供单一的全局访问点。构造函数设为 protected/private,通过 getInstance() 获取唯一实例,有懒汉和饿汉两种初始化策略。
工厂方法 Factory Method
提供延迟创建类的方法,在运行期由子类决定创建哪一个类的实例,避免类名的硬编码,提高移植性和复用性。
抽象工厂 Abstract Factory
为一系列具有相似基类或接口的对象提供一致的创建接口。根据不同配置/上下文加载接口一致但实现不同的类实例,CreateProduct() 与 AbstractProduct 一一对应。
适配器 Adapter
解决系统间接口不相容问题,把类的接口转化为客户程序所希望的接口,从而提高复用性。
桥接 Bridge
将类的抽象部分与实现部分分离,使抽象和实现可以独立地变化。
组合 Composite
以树形结构组合对象,使单个对象和组合后的对象具有一致性,提高软件复用性。
装饰 Decorator
动态为对象方法增加功能,无需继承出大量子类,维护简洁的类继承结构。又称油漆工模式。
外观 Facade
为一组类提供一致的访问接口,封装子系统内部结构,降低客户程序与子系统的耦合。J2EE 中发展为 Session Facade。
代理 Proxy
为对象提供访问代理,控制客户程序的访问权限、地址、方式等,可将开销较大的访问化整为零提高效率。
观察者 Observer
将对象状态广播到一组观察者,每个观察者可随时获得更新通知。实现一对多依赖的抽象耦合,即发布-订阅机制。
策略 Strategy
让对象中算法的变化独立于客户,将不同算法封装为可互换的策略对象。
模板方法 Template Method
定义一个操作的模板,其中部分步骤在子类中实现,以适应不同情况。
状态 State
允许一个对象在其内部状态改变时改变其行为。
GoF 23种设计模式分类
| 类别 | 模式 | 意图(简) |
|---|---|---|
| 创建型(5种) | Factory Method(工厂方法) | 延迟创建类,运行期由子类决定实例化哪个类 |
| Abstract Factory(抽象工厂) | 为一系列相似对象提供一致的创建接口 | |
| Builder(构建器) | 逐步构造复杂对象,将创建与表示分离 | |
| Prototype(原型) | 通过深复制原型实例创建新对象,运行期指定 | |
| Singleton(单例) | 保证一个类仅有一个实例,提供全局访问点 | |
| 结构型(7种) | Adapter(适配器) | 将不兼容接口转换为客户希望的接口 |
| Bridge(桥接) | 分离抽象部分与实现部分,二者独立变化 | |
| Composite(组合) | 树形结构组合对象,单个与组合对象一致 | |
| Decorator(装饰) | 动态为对象方法增加功能,避免子类膨胀 | |
| Facade(外观) | 为一组类提供一致访问接口,封装子系统 | |
| Flyweight(享元) | 共享大量细粒度对象,节省空间(时间开销增大) | |
| Proxy(代理) | 为对象提供访问代理,控制访问权限/地址/方式 | |
| 行为型(11种) | Interpreter(解释器) | 定义解释器,解释遵循给定语言和文法的句子 |
| Template Method(模板方法) | 定义操作模板,部分步骤在子类中实现 | |
| Chain of Responsibility(职责链) | 将响应对象组成链并传递请求,解耦请求方与响应方 | |
| Command(命令) | 将请求封装为对象,支持参数化、排队、日志 | |
| Iterator(迭代器) | 顺序访问集合元素,不暴露内部结构 | |
| Mediator(中介者) | 用中介对象封装对象间通信,降低耦合 | |
| Memento(备忘录) | 捕获并外部保存对象状态,不破坏封装 | |
| Observer(观察者) | 状态变化广播到一组观察者,发布-订阅 | |
| State(状态) | 对象内部状态改变时改变其行为 | |
| Strategy(策略) | 算法变化独立于客户,可互换 | |
| Visitor(访问者) | 在不改变元素类前提下定义新操作 |
关键规则与原则
考试要点
- 23种模式分类必考:创建型5种、结构型7种、行为型11种,牢记数量与归属。
- 单例两种实现:懒汉式(Lazy Initialization,延迟加载)与饿汉式(Early Initialization,类加载即创建),注意 Singleton 不支持继承,不等同于 static 类。
- 工厂方法 vs 抽象工厂:工厂方法由子类决定实例化哪个类;抽象工厂提供一系列相关对象的统一创建接口,CreateProduct() 与 AbstractProduct 一一对应。
- 适配器 vs 桥接 vs 装饰:适配器=接口转换(解决不兼容);桥接=分离抽象与实现(二者独立变化);装饰=动态增加职责(避免子类膨胀)。
- 代理 vs 装饰:代理侧重控制访问(权限/地址/方式),装饰侧重动态扩展功能;两者都在对象前增加一层,但目的不同。
- 观察者=发布订阅:一对多依赖抽象耦合,Subject 通过 attach/detach 管理观察者,notify 广播更新。注意避免广播风暴,update 中不能反向更新 Subject。
- 策略 vs 状态:策略=算法变化独立于客户(客户主动选择);状态=对象内部状态改变时自动改变行为。
- 模板方法=钩子:定义操作骨架,具体步骤延迟到子类实现。
- Intercepting Filter:J2EE 模式,与 Decorator 类似但在处理对象前增加预处理层,可与工厂模式结合动态创建 Filter。
- 设计模式不可滥用:简单系统中过度使用反而增加复杂度,重构是应用模式的良好时机。
关键图示
图10-1 Abstract Factory 模式结构 — 抽象工厂接受Client订单,由不同车间生产特定产品
图10-5 Decorator 模式顺序图 — 运行期根据客户选择动态扩展功能
图10-9 Mediator 模式结构 — Colleague 通过 ConcreteMediator 中介类进行通信