10.5.5 行为型设计模式-02
这一节继续行为型模式,重点是几个高频易混项:状态、策略、模板方法、访问者,以及它们与观察者、桥接、中介者的区别。
状态模式:把状态封装成类
状态模式允许一个对象在内部状态改变时改变它的行为。它的核心做法是:把不同状态封装为不同状态类。
classDiagram
class Context {
-State state
+request()
+setState(state)
}
class State {
+handle()
}
class SoldOutState
class HasMoneyState
class SoldState
Context --> State
State <|.. SoldOutState
State <|.. HasMoneyState
State <|.. SoldState课程用自动售货机场景说明:根据库存、存入金额、找零能力、所选项目等不同情况,系统会有不同状态和不同行为。类图中出现 State,并且每个具体类对应一个状态时,通常就是状态模式。
状态模式与 UML 状态图有联系:状态图中的状态节点,如果进一步设计成状态类,就进入了状态模式的实现层。
策略模式:把算法封装成类
策略模式定义一系列算法,把每个算法封装起来,使它们可以互相替换。策略变化不应影响使用策略的客户。
classDiagram
class Context {
-Strategy strategy
+calculate()
}
class Strategy {
+algorithm()
}
class GoldDiscount
class SilverDiscount
class NoDiscount
Context --> Strategy
Strategy <|.. GoldDiscount
Strategy <|.. SilverDiscount
Strategy <|.. NoDiscount状态和策略类图相似,但语义不同:
| 对比项 | 状态模式 | 策略模式 |
|---|---|---|
| 封装对象 | 状态 | 算法/方案 |
| 变化原因 | 对象内部状态变化 | 客户选择不同算法 |
| 行为变化 | 状态变了,行为随之变 | 算法替换,计算方式变 |
| 典型例子 | 会员等级状态升级导致行为变化 | 金卡折扣、银卡折扣、普通折扣算法 |
如果题干强调“内部状态改变时行为改变”,选状态;如果强调“一组算法可以互换”,选策略。
模板方法:父类定义算法骨架
模板方法在父类中定义算法骨架,把某些具体步骤延迟到子类实现。它不是把完整算法封装成可互换对象,而是规定流程框架,让子类填写变化步骤。
classDiagram
class AbstractClass {
+templateMethod()
#step1()
#step2()
}
class ConcreteClassA
class ConcreteClassB
AbstractClass <|-- ConcreteClassA
AbstractClass <|-- ConcreteClassB课程用文档模板填空来记忆:合同模板的结构不变,空白处由不同人填写。模板方法的关键词是“算法骨架”“步骤延迟到子类”“不改变算法结构”。
| 对比项 | 策略模式 | 模板方法 |
|---|---|---|
| 变化方式 | 通过组合替换算法对象 | 通过继承重写部分步骤 |
| 固定内容 | 客户持有策略接口 | 父类固定算法骨架 |
| 关键词 | 算法可互换 | 算法骨架固定,步骤可变 |
访问者:数据与操作分离
访问者模式表示一个作用于对象结构中各元素的操作。它可以在不改变元素类的前提下,定义作用于这些元素的新操作。
课程强调两个判断点:
- 访问者中常有
visit()方法。 - 元素中常有
accept(visitor)方法。
classDiagram
class Visitor {
+visitItemA(item)
+visitItemB(item)
}
class CheckoutVisitor
class Element {
+accept(visitor)
}
class ItemA
class ItemB
class ObjectStructure {
+accept(visitor)
}
Visitor <|.. CheckoutVisitor
Element <|.. ItemA
Element <|.. ItemB
ObjectStructure o-- Element
Element ..> Visitor : accept()访问者适合对象结构相对稳定,但对这些对象要增加很多不同操作的场景。例如购物车里有多种商品元素,人工结账、自助结账、促销统计等是不同访问方式。访问方式选定后,会依次访问所有元素。
访问者与桥接、观察者、策略的区分
| 易混项 | 为什么像 | 真正区别 |
|---|---|---|
| 访问者 vs 桥接 | 都可能有两个变化维度 | 桥接把两个维度组合起来;访问者选择一种访问方式去遍历对象结构 |
| 访问者 vs 观察者 | 名字都带“者”,都有对象关系 | 观察者是一对多联动;访问者是数据与操作分离 |
| 访问者 vs 策略 | 都有“选择一种方式” | 策略只封装算法;访问者要访问另一侧对象结构中的所有元素 |
访问者的强项是增加新操作方便;弱点是如果元素类频繁变化,就要改很多访问者。因此它适合“对象结构稳定、操作经常变化”的系统。
行为型真题判断层次
课程总结了设计模式判断的三个层次,在行为型题里尤其明显:
- 应用场景匹配:自动售货机状态变化、购物车结算、后端模型连接多个前端界面。
- 类名/方法名识别:
State、Command、Visitor、accept()、visit()。 - 意图排除:观察者是一对多通知,备忘录是保存状态,命令是请求对象化,职责链是层层传递。
例如自动售货机题,如果类图里有 State,并且不同状态对应不同处理行为,就选状态模式;超市销售系统如果出现 accept() 并把商品条目与结账方式分离,就选访问者模式。
例题
自查要点
- 状态模式和策略模式为什么类图相似但意图不同?
- 模板方法和策略都涉及算法,区别在哪里?
- 访问者的
visit()和accept()分别在哪一侧? - 为什么对象结构频繁变化时不适合访问者模式?