跳转至

04-行为型模式

学习时间: 约 5-6 小时 难度级别: ⭐⭐⭐⭐ 中高级 前置知识: SOLID 设计原则、创建型模式、结构型模式 学习目标: 掌握 11 种行为型模式,理解对象间职责分配与通信机制


🎯 学习目标

  1. 掌握策略、观察者、命令三大高频行为型模式
  2. 理解模板方法与策略模式的异同
  3. 掌握 Python 迭代器协议与迭代器模式的关系
  4. 理解责任链模式在中间件系统中的应用
  5. 能根据场景选择合适的行为型模式

目录


1. 行为型模式概述

行为型模式关注对象之间的职责分配通信方式,让复杂的控制流变得清晰。

模式 一句话 使用频率
策略 算法可互换 ⭐⭐⭐⭐⭐
观察者 事件通知 ⭐⭐⭐⭐⭐
命令 操作对象化 ⭐⭐⭐⭐
模板方法 骨架+钩子 ⭐⭐⭐⭐
迭代器 统一遍历 ⭐⭐⭐⭐
状态 状态驱动行为 ⭐⭐⭐⭐
责任链 链式处理 ⭐⭐⭐⭐
中介者 集中协调 ⭐⭐⭐
备忘录 状态快照 ⭐⭐⭐
访问者 分离操作与结构 ⭐⭐
解释器 语法解析 ⭐⭐

2. 策略模式( Strategy )

意图

定义一系列算法,将每个算法封装起来,使它们可以互换

适用场景

  • 多种方式处理同一问题(排序、计价、验证等)
  • 消除大量 if/elif/else 分支
  • 算法需要在运行时动态切换

Python 实现

Python
from abc import ABC, abstractmethod
from typing import List

# ====== 策略接口 ======
class PricingStrategy(ABC):
    @abstractmethod
    def calculate(self, price: float) -> float:
        pass

# ====== 具体策略 ======
class NormalPricing(PricingStrategy):
    def calculate(self, price):
        return price

class VIPPricing(PricingStrategy):
    def calculate(self, price):
        return price * 0.8  # 8折

class PromotionPricing(PricingStrategy):
    def __init__(self, discount_rate):
        self.discount_rate = discount_rate

    def calculate(self, price):
        return price * self.discount_rate

class SecondHalfPrice(PricingStrategy):
    """第二件半价"""
    def calculate(self, price):
        return price * 0.75  # 两件均价

# ====== 上下文 ======
class ShoppingCart:
    def __init__(self, strategy: PricingStrategy = None):
        self._strategy = strategy or NormalPricing()
        self._items: List[tuple] = []

    def set_strategy(self, strategy: PricingStrategy):
        """运行时切换策略"""
        self._strategy = strategy

    def add_item(self, name, price):
        self._items.append((name, price))

    def total(self):
        return sum(self._strategy.calculate(p) for _, p in self._items)

# ====== 使用 ======
cart = ShoppingCart()
cart.add_item("Book", 100)
cart.add_item("Pen", 50)

print(f"Normal: ¥{cart.total()}")        # 150
cart.set_strategy(VIPPricing())
print(f"VIP: ¥{cart.total()}")            # 120
cart.set_strategy(PromotionPricing(0.6))
print(f"Promotion: ¥{cart.total()}")      # 90

Python 函数式简化

Python 中可以直接用函数代替策略类:

Python
from typing import Callable

def normal(price): return price
def vip(price): return price * 0.8
def promotion(price, rate=0.6): return price * rate

class ShoppingCartFP:
    def __init__(self, strategy: Callable = normal):
        self.strategy = strategy
        self.items = []

    def add(self, name, price):
        self.items.append((name, price))

    def total(self):
        return sum(self.strategy(p) for _, p in self.items)

cart = ShoppingCartFP(strategy=vip)
cart.add("Book", 100)
print(cart.total())  # 80.0

Java 实现

Java
public interface PricingStrategy {
    double calculate(double price);
}

public class VIPPricing implements PricingStrategy {  // extends继承;implements实现接口
    public double calculate(double price) { return price * 0.8; }
}

public class ShoppingCart {
    private PricingStrategy strategy;

    public void setStrategy(PricingStrategy strategy) {
        this.strategy = strategy;
    }

    public double getTotal() {
        return items.stream()
            .mapToDouble(item -> strategy.calculate(item.price))
            .sum();
    }
}

3. 观察者模式( Observer )

意图

定义对象间的一对多依赖关系,当一个对象状态改变时,所有依赖者自动通知

适用场景

  • 事件系统( GUI 事件、 DOM 事件)
  • 发布-订阅(消息队列、 RSS )
  • 数据绑定( MVVM )

Python 实现

Python
from abc import ABC, abstractmethod
from typing import Dict, List, Callable

# ====== 方式一:经典OOP实现 ======
class EventManager:
    """事件管理器(发布-订阅)"""
    def __init__(self):
        self._listeners: Dict[str, List[Callable]] = {}

    def subscribe(self, event_type: str, listener: Callable):
        if event_type not in self._listeners:
            self._listeners[event_type] = []
        self._listeners[event_type].append(listener)

    def unsubscribe(self, event_type: str, listener: Callable):
        if event_type in self._listeners:
            self._listeners[event_type].remove(listener)

    def notify(self, event_type: str, data=None):
        for listener in self._listeners.get(event_type, []):
            listener(data)

# ====== 具体发布者 ======
class UserService:
    def __init__(self):
        self.events = EventManager()

    def register(self, username, email):
        user = {"username": username, "email": email}
        print(f"User registered: {username}")
        # 注册成功后发布事件
        self.events.notify("user_registered", user)

    def login(self, username):
        print(f"User logged in: {username}")
        self.events.notify("user_logged_in", {"username": username})

# ====== 具体订阅者 ======
class EmailService:
    def send_welcome(self, user):
        print(f"  📧 Sending welcome email to {user['email']}")

class AnalyticsService:
    def track_registration(self, user):
        print(f"  📊 Tracking registration: {user['username']}")

class NotificationService:
    def on_login(self, data):
        print(f"  🔔 Login notification: {data['username']}")

# ====== 组装 ======
user_service = UserService()

email = EmailService()
analytics = AnalyticsService()
notification = NotificationService()

# 订阅事件
user_service.events.subscribe("user_registered", email.send_welcome)
user_service.events.subscribe("user_registered", analytics.track_registration)
user_service.events.subscribe("user_logged_in", notification.on_login)

# 触发事件
user_service.register("alice", "alice@example.com")
# User registered: alice
#   📧 Sending welcome email to alice@example.com
#   📊 Tracking registration: alice

user_service.login("alice")
# User logged in: alice
#   🔔 Login notification: alice

方式二: Python 信号机制

Python
# 使用 blinker 库实现信号(类似Django的signals)
from collections import defaultdict  # defaultdict带默认值的字典,避免KeyError

class Signal:
    """简化版信号实现"""
    def __init__(self, name=""):
        self.name = name
        self._receivers = []

    def connect(self, func):
        """装饰器方式注册"""
        self._receivers.append(func)
        return func

    def send(self, sender=None, **kwargs):  # *args接收任意位置参数;**kwargs接收任意关键字参数
        results = []
        for receiver in self._receivers:
            results.append(receiver(sender, **kwargs))
        return results

# 定义信号
user_registered = Signal("user_registered")
order_created = Signal("order_created")

# 注册处理器
@user_registered.connect
def handle_new_user(sender, **kwargs):
    print(f"New user: {kwargs.get('username')}")

@user_registered.connect
def send_email(sender, **kwargs):
    print(f"Sending email to: {kwargs.get('email')}")

# 触发
user_registered.send(None, username="bob", email="bob@test.com")

注意事项

⚠️ 内存泄漏风险:观察者模式最常见的隐患是忘记取消订阅。如果订阅者对象已经不再使用但未调用 unsubscribe(),发布者仍然持有其引用,导致订阅者无法被垃圾回收,造成内存泄漏。

最佳实践: - 在订阅者销毁/关闭时,务必调用 unsubscribe() 清理所有订阅 - Python 可使用 weakref 弱引用避免强引用导致的泄漏 - Java 中考虑使用 WeakReference 或在 close()/dispose() 方法中集中清理 - 长生命周期的发布者 + 短生命周期的订阅者是最高危组合

Java 实现

Java
import java.util.*;

public interface EventListener {  // interface定义类型契约
    void update(String eventType, Object data);
}

public class EventManager {
    private Map<String, List<EventListener>> listeners = new HashMap<>();

    public void subscribe(String type, EventListener listener) {
        listeners.computeIfAbsent(type, k -> new ArrayList<>()).add(listener);
    }

    public void notify(String type, Object data) {
        for (EventListener l : listeners.getOrDefault(type, List.of())) {
            l.update(type, data);
        }
    }
}

4. 命令模式( Command )

意图

请求封装为一个对象,从而支持撤销、排队、日志等操作。

Python 实现

Python
from abc import ABC, abstractmethod
from typing import List

# ====== 命令接口 ======
class Command(ABC):
    @abstractmethod
    def execute(self): pass

    @abstractmethod
    def undo(self): pass

# ====== 接收者 ======
class TextEditor:
    def __init__(self):
        self.content = ""

    def insert(self, text, position=-1):
        if position == -1:
            self.content += text
        else:
            self.content = self.content[:position] + text + self.content[position:]

    def delete(self, start, length):
        deleted = self.content[start:start + length]
        self.content = self.content[:start] + self.content[start + length:]
        return deleted

    def __str__(self):
        return f"'{self.content}'"

# ====== 具体命令 ======
class InsertCommand(Command):
    def __init__(self, editor: TextEditor, text: str, position: int = -1):
        self.editor = editor
        self.text = text
        self.position = position

    def execute(self):
        self.editor.insert(self.text, self.position)

    def undo(self):
        if self.position == -1:
            pos = len(self.editor.content) - len(self.text)
        else:
            pos = self.position
        self.editor.delete(pos, len(self.text))

class DeleteCommand(Command):
    def __init__(self, editor: TextEditor, start: int, length: int):
        self.editor = editor
        self.start = start
        self.length = length
        self._deleted = ""

    def execute(self):
        self._deleted = self.editor.delete(self.start, self.length)

    def undo(self):
        self.editor.insert(self._deleted, self.start)

# ====== 调用者(支持撤销/重做) ======
class CommandManager:
    def __init__(self):
        self._history: List[Command] = []
        self._redo_stack: List[Command] = []

    def execute(self, command: Command):
        command.execute()
        self._history.append(command)
        self._redo_stack.clear()

    def undo(self):
        if not self._history:
            print("Nothing to undo!")
            return
        command = self._history.pop()
        command.undo()
        self._redo_stack.append(command)

    def redo(self):
        if not self._redo_stack:
            print("Nothing to redo!")
            return
        command = self._redo_stack.pop()
        command.execute()
        self._history.append(command)

# ====== 使用 ======
editor = TextEditor()
manager = CommandManager()

manager.execute(InsertCommand(editor, "Hello"))
print(editor)  # 'Hello'

manager.execute(InsertCommand(editor, " World"))
print(editor)  # 'Hello World'

manager.undo()
print(editor)  # 'Hello'

manager.redo()
print(editor)  # 'Hello World'

manager.execute(DeleteCommand(editor, 5, 6))
print(editor)  # 'Hello'

实际应用

  • 文本编辑器的撤销/重做
  • GUI 框架的按钮/菜单操作绑定
  • 数据库事务
  • 任务队列和调度系统

5. 模板方法模式( Template Method )

意图

定义算法的骨架,将某些步骤延迟到子类实现。

Python 实现

Python
from abc import ABC, abstractmethod

class DataProcessor(ABC):
    """模板方法定义处理流程骨架"""

    def process(self, source):
        """模板方法 — 定义算法骨架,不可覆盖"""
        data = self.read_data(source)
        parsed = self.parse_data(data)
        if self.should_validate():  # 钩子方法
            self.validate(parsed)
        result = self.transform(parsed)
        self.save(result)
        return result

    @abstractmethod
    def read_data(self, source):
        """抽象方法 — 子类必须实现"""
        pass

    @abstractmethod
    def parse_data(self, raw_data):
        pass

    def should_validate(self):
        """钩子方法 — 子类可选择覆盖"""
        return True

    def validate(self, data):
        print(f"Validating {len(data)} records")

    @abstractmethod
    def transform(self, data):
        pass

    def save(self, result):
        print(f"Saved {len(result)} records")

class CSVProcessor(DataProcessor):
    def read_data(self, source):
        print(f"Reading CSV: {source}")
        return "name,age\nAlice,25\nBob,30"

    def parse_data(self, raw_data):
        lines = raw_data.strip().split("\n")
        headers = lines[0].split(",")
        return [dict(zip(headers, line.split(","))) for line in lines[1:]]  # zip并行遍历多个可迭代对象

    def transform(self, data):
        return [{**d, "age": int(d["age"])} for d in data]

class JSONProcessor(DataProcessor):
    def read_data(self, source):
        print(f"Reading JSON: {source}")
        return '[{"name":"Alice","age":25}]'

    def parse_data(self, raw_data):
        import json
        return json.loads(raw_data)  # json.loads将JSON字符串转为Python对象

    def should_validate(self):
        return False  # JSON自带格式校验,跳过

    def transform(self, data):
        return data

# 使用
csv_processor = CSVProcessor()
csv_processor.process("data.csv")

json_processor = JSONProcessor()
json_processor.process("data.json")

策略 vs 模板方法

策略模式 模板方法
粒度 替换整个算法 替换算法的某些步骤
关系 组合( has-a ) 继承( is-a )
灵活性 运行时切换 编译时确定

6. 迭代器模式( Iterator )

意图

提供一种方法顺序访问集合中的元素,而不暴露集合的内部结构。

Python 迭代器协议

Python 内置了迭代器模式支持,通过 __iter__()__next__() 实现:

Python
class FibonacciIterator:
    """斐波那契数列迭代器"""
    def __init__(self, max_count):
        self.max_count = max_count
        self.count = 0
        self.a, self.b = 0, 1

    def __iter__(self):
        return self

    def __next__(self):
        if self.count >= self.max_count:
            raise StopIteration
        self.count += 1
        result = self.a
        self.a, self.b = self.b, self.a + self.b
        return result

# 使用
for num in FibonacciIterator(10):
    print(num, end=" ")
# 0 1 1 2 3 5 8 13 21 34

# ====== 自定义可迭代集合 ======
class TreeNode:
    def __init__(self, value, children=None):
        self.value = value
        self.children = children or []

class TreeIterator:
    """树的深度优先迭代器"""
    def __init__(self, root: TreeNode):
        self._stack = [root]

    def __iter__(self):
        return self

    def __next__(self):
        if not self._stack:
            raise StopIteration
        node = self._stack.pop()
        # 逆序压栈,保证左子节点先出
        self._stack.extend(reversed(node.children))
        return node.value

class Tree:
    def __init__(self, root: TreeNode):
        self.root = root

    def __iter__(self):
        return TreeIterator(self.root)

# 构建树并遍历
tree = Tree(TreeNode("root", [
    TreeNode("A", [TreeNode("A1"), TreeNode("A2")]),
    TreeNode("B", [TreeNode("B1")]),
]))

print(list(tree))  # ['root', 'A', 'A1', 'A2', 'B', 'B1']

生成器:更 Pythonic 的迭代器

Python
def fibonacci(max_count):
    """生成器函数 — 等价于FibonacciIterator但更简洁"""
    a, b = 0, 1
    for _ in range(max_count):
        yield a  # yield生成器:惰性产出值,节省内存
        a, b = b, a + b

# 树的深度优先遍历(生成器版)
def dfs(node):
    yield node.value
    for child in node.children:
        yield from dfs(child)  # yield from 递归委托

print(list(fibonacci(8)))  # [0, 1, 1, 2, 3, 5, 8, 13]

7. 状态模式( State )

意图

允许对象在内部状态改变时改变其行为,对象看起来好像修改了其类。

Python 实现

Python
from abc import ABC, abstractmethod

# ====== 状态接口 ======
class OrderState(ABC):
    @abstractmethod
    def pay(self, order): pass

    @abstractmethod
    def ship(self, order): pass

    @abstractmethod
    def deliver(self, order): pass

    @abstractmethod
    def cancel(self, order): pass

# ====== 具体状态 ======
class PendingState(OrderState):
    def pay(self, order):
        print("✅ Payment received!")
        order.state = PaidState()

    def ship(self, order):
        print("❌ Cannot ship: not paid yet")

    def deliver(self, order):
        print("❌ Cannot deliver: not paid yet")

    def cancel(self, order):
        print("✅ Order cancelled")
        order.state = CancelledState()

class PaidState(OrderState):
    def pay(self, order):
        print("❌ Already paid")

    def ship(self, order):
        print("✅ Order shipped!")
        order.state = ShippedState()

    def deliver(self, order):
        print("❌ Cannot deliver: not shipped yet")

    def cancel(self, order):
        print("✅ Refunding and cancelling")
        order.state = CancelledState()

class ShippedState(OrderState):
    def pay(self, order): print("❌ Already paid")
    def ship(self, order): print("❌ Already shipped")

    def deliver(self, order):
        print("✅ Order delivered!")
        order.state = DeliveredState()

    def cancel(self, order):
        print("❌ Cannot cancel: already shipped")

class DeliveredState(OrderState):
    def pay(self, order): print("❌ Already completed")
    def ship(self, order): print("❌ Already completed")
    def deliver(self, order): print("❌ Already delivered")
    def cancel(self, order): print("❌ Cannot cancel: already delivered")

class CancelledState(OrderState):
    def pay(self, order): print("❌ Order cancelled")
    def ship(self, order): print("❌ Order cancelled")
    def deliver(self, order): print("❌ Order cancelled")
    def cancel(self, order): print("❌ Already cancelled")

# ====== 上下文 ======
class Order:
    def __init__(self, order_id):
        self.order_id = order_id
        self.state: OrderState = PendingState()

    def pay(self): self.state.pay(self)
    def ship(self): self.state.ship(self)
    def deliver(self): self.state.deliver(self)
    def cancel(self): self.state.cancel(self)

    @property
    def status(self):
        return self.state.__class__.__name__.replace("State", "")

# 使用
order = Order("ORD-001")
print(f"Status: {order.status}")  # Pending
order.ship()     # ❌ Cannot ship: not paid yet
order.pay()      # ✅ Payment received!
print(f"Status: {order.status}")  # Paid
order.ship()     # ✅ Order shipped!
order.deliver()  # ✅ Order delivered!
order.cancel()   # ❌ Cannot cancel: already delivered

状态 vs 策略

状态模式 策略模式
状态转换 状态之间互相知道,自动转换 策略互不知道
切换方式 内部自动 外部手动
意图 管理状态机 替换算法

8. 责任链模式( Chain of Responsibility )

意图

将请求沿着处理者传递,每个处理者可以处理请求或传递给下一个。

Python 实现

Python
from abc import ABC, abstractmethod
from typing import Optional

# ====== 中间件/处理器基类 ======
class Middleware(ABC):
    def __init__(self):
        self._next: Optional[Middleware] = None

    def set_next(self, handler: 'Middleware') -> 'Middleware':
        self._next = handler
        return handler  # 支持链式设置

    def handle(self, request: dict) -> dict:
        if self._next:
            return self._next.handle(request)
        return request

# ====== 具体中间件 ======
class AuthMiddleware(Middleware):
    def handle(self, request):
        token = request.get("token")
        if not token:
            return {"error": "401 Unauthorized"}
        if token != "valid_token":
            return {"error": "403 Forbidden"}
        print("  ✅ Auth passed")
        request["user"] = "alice"
        return super().handle(request)  # super()调用父类方法

class RateLimitMiddleware(Middleware):
    def __init__(self, max_requests=100):
        super().__init__()
        self.max_requests = max_requests
        self._count = 0

    def handle(self, request):
        self._count += 1
        if self._count > self.max_requests:
            return {"error": "429 Too Many Requests"}
        print(f"  ✅ Rate limit OK ({self._count}/{self.max_requests})")
        return super().handle(request)

class LoggingMiddleware(Middleware):
    def handle(self, request):
        print(f"  📝 Request: {request.get('path', '/')}")
        response = super().handle(request)
        print(f"  📝 Response: {response}")
        return response

class ValidationMiddleware(Middleware):
    def handle(self, request):
        if not request.get("path"):
            return {"error": "400 Bad Request: missing path"}
        print("  ✅ Validation passed")
        return super().handle(request)

# ====== 构建中间件链 ======
logging = LoggingMiddleware()
rate_limit = RateLimitMiddleware(max_requests=10)
auth = AuthMiddleware()
validation = ValidationMiddleware()

# 设置链: Logging → RateLimit → Auth → Validation
logging.set_next(rate_limit).set_next(auth).set_next(validation)

# 处理请求
print("--- Request 1 (valid) ---")
result = logging.handle({"path": "/api/data", "token": "valid_token"})

print("\n--- Request 2 (no token) ---")
result = logging.handle({"path": "/api/data"})

实际应用

  • Web 框架中间件( Django Middleware 、 Express.js Middleware )
  • Java Servlet Filter 链
  • 日志框架的 Handler 链
  • GUI 事件冒泡机制

9. 中介者模式( Mediator )

意图

用一个中介对象来封装一系列对象之间的交互,使各对象不需要直接引用彼此。

Python 实现

Python
from abc import ABC, abstractmethod

class ChatRoom:
    """中介者:聊天室"""
    def __init__(self, name):
        self.name = name
        self._users = {}

    def join(self, user):
        self._users[user.name] = user
        user.room = self
        self._broadcast(f"[{user.name} joined the room]", sender=None)

    def send(self, message, sender, target=None):
        if target:
            # 私聊
            if target in self._users:
                self._users[target].receive(message, sender.name, private=True)
        else:
            # 群发
            self._broadcast(message, sender)

    def _broadcast(self, message, sender):
        for name, user in self._users.items():
            if sender is None or name != sender.name:
                user.receive(message, sender.name if sender else "System")

class User:
    def __init__(self, name):
        self.name = name
        self.room: ChatRoom = None

    def send(self, message, target=None):
        if self.room:
            self.room.send(message, self, target)

    def receive(self, message, sender, private=False):
        tag = "[DM]" if private else ""
        print(f"  {self.name} received {tag} from {sender}: {message}")

# 使用
room = ChatRoom("dev-chat")
alice = User("Alice")
bob = User("Bob")
charlie = User("Charlie")

room.join(alice)
room.join(bob)
room.join(charlie)

alice.send("Hello everyone!")   # Bob和Charlie收到
bob.send("Hi Alice!", "Alice")  # 仅Alice收到(私聊)

10. 备忘录模式( Memento )

意图

在不破坏封装性的前提下,捕获和恢复对象的内部状态。

Python 实现

Python
import copy
from datetime import datetime

class EditorMemento:
    """备忘录:保存编辑器状态快照"""
    def __init__(self, content, cursor_pos, selection):
        self._content = content
        self._cursor_pos = cursor_pos
        self._selection = selection
        self._timestamp = datetime.now()

    @property  # @property将方法变为属性访问
    def timestamp(self):
        return self._timestamp

    @property
    def description(self):
        preview = self._content[:30] + "..." if len(self._content) > 30 else self._content  # 切片操作:[start:end:step]提取子序列
        return f"[{self._timestamp.strftime('%H:%M:%S')}] '{preview}'"

class Editor:
    """发起者:文本编辑器"""
    def __init__(self):
        self.content = ""
        self.cursor_pos = 0
        self.selection = ""

    def type_text(self, text):
        self.content += text
        self.cursor_pos = len(self.content)

    def save(self) -> EditorMemento:
        return EditorMemento(
            copy.copy(self.content),
            self.cursor_pos,
            self.selection
        )

    def restore(self, memento: EditorMemento):
        self.content = memento._content
        self.cursor_pos = memento._cursor_pos
        self.selection = memento._selection

class History:
    """管理者:保存备忘录历史"""
    def __init__(self, editor: Editor):
        self._editor = editor
        self._snapshots = []

    def backup(self):
        self._snapshots.append(self._editor.save())

    def undo(self):
        if not self._snapshots:
            return
        memento = self._snapshots.pop()
        self._editor.restore(memento)

    def show_history(self):
        for i, s in enumerate(self._snapshots):  # enumerate同时获取索引和值
            print(f"  {i}: {s.description}")

# 使用
editor = Editor()
history = History(editor)

editor.type_text("Hello")
history.backup()

editor.type_text(" World")
history.backup()

editor.type_text("!!!")
print(f"Current: '{editor.content}'")  # Hello World!!!

history.undo()
print(f"After undo: '{editor.content}'")  # Hello World

history.undo()
print(f"After undo: '{editor.content}'")  # Hello

11. 访问者模式( Visitor )

意图

在不修改类结构的前提下,定义新的操作。将算法与数据结构分离。

Python 实现

Python
from abc import ABC, abstractmethod

# ====== 元素 ======
class Shape(ABC):
    @abstractmethod
    def accept(self, visitor): pass

class Circle(Shape):
    def __init__(self, radius):
        self.radius = radius

    def accept(self, visitor):
        return visitor.visit_circle(self)

class Rectangle(Shape):
    def __init__(self, width, height):
        self.width = width
        self.height = height

    def accept(self, visitor):
        return visitor.visit_rectangle(self)

# ====== 访问者 ======
class ShapeVisitor(ABC):
    @abstractmethod
    def visit_circle(self, circle): pass
    @abstractmethod
    def visit_rectangle(self, rect): pass

class AreaCalculator(ShapeVisitor):
    """计算面积的访问者"""
    def visit_circle(self, c):
        import math
        return math.pi * c.radius ** 2

    def visit_rectangle(self, r):
        return r.width * r.height

class DrawVisitor(ShapeVisitor):
    """绘制的访问者"""
    def visit_circle(self, c):
        return f"Drawing circle with r={c.radius}"

    def visit_rectangle(self, r):
        return f"Drawing rectangle {r.width}x{r.height}"

# 新增操作不需要修改Shape类
shapes = [Circle(5), Rectangle(3, 4), Circle(10)]

area_calc = AreaCalculator()
total = sum(s.accept(area_calc) for s in shapes)
print(f"Total area: {total:.2f}")

drawer = DrawVisitor()
for s in shapes:
    print(s.accept(drawer))

适用场景:数据结构稳定但操作频繁变化时使用。编译器中常用于对 AST 的多种遍历处理。


12. 解释器模式( Interpreter )

意图

给定一个语言,定义其文法的一种表示,并用解释器来解释该语言中的句子。

Python 简化实现

Python
from abc import ABC, abstractmethod  # ABC抽象基类;abstractmethod强制子类实现

class Expression(ABC):
    @abstractmethod
    def interpret(self, context: dict) -> bool:
        pass

class VariableExpression(Expression):
    def __init__(self, name):
        self.name = name

    def interpret(self, context):
        return context.get(self.name, False)

class AndExpression(Expression):
    def __init__(self, left, right):
        self.left = left
        self.right = right

    def interpret(self, context):
        return self.left.interpret(context) and self.right.interpret(context)

class OrExpression(Expression):
    def __init__(self, left, right):
        self.left = left
        self.right = right

    def interpret(self, context):
        return self.left.interpret(context) or self.right.interpret(context)

class NotExpression(Expression):
    def __init__(self, expr):
        self.expr = expr

    def interpret(self, context):
        return not self.expr.interpret(context)

# 构建规则: (is_vip AND has_balance) OR is_admin
rule = OrExpression(
    AndExpression(VariableExpression("is_vip"), VariableExpression("has_balance")),
    VariableExpression("is_admin")
)

print(rule.interpret({"is_vip": True, "has_balance": True, "is_admin": False}))   # True
print(rule.interpret({"is_vip": True, "has_balance": False, "is_admin": False}))  # False
print(rule.interpret({"is_vip": False, "has_balance": False, "is_admin": True}))  # True

实际应用:正则表达式引擎、 SQL 解析器、规则引擎。因复杂度高,实际项目中较少直接手写。


13. 行为型模式对比

高频模式选择指南

Text Only
需要替换算法?           → 策略模式
需要事件通知?           → 观察者模式
需要撤销/重做?          → 命令模式
需要定义算法骨架?       → 模板方法
需要遍历集合?           → 迭代器模式
对象行为随状态改变?     → 状态模式
请求需要链式处理?       → 责任链模式
多对象复杂交互?         → 中介者模式
需要保存/恢复状态?      → 备忘录模式
数据结构稳定但操作常变? → 访问者模式

容易混淆的模式

对比 区别
策略 vs 状态 策略外部切换算法;状态内部自动转换
命令 vs 策略 命令封装操作(可撤销);策略封装算法
观察者 vs 中介者 观察者是分布式通知;中介者是集中式协调
模板方法 vs 策略 模板方法用继承覆盖步骤;策略用组合替换整体

14. 练习与自我检查

✏️ 练习题

  1. 策略模式:实现一个日志系统,支持多种输出策略(控制台、文件、远程服务器),可在运行时切换。

  2. 观察者模式:实现一个股票价格监控系统,当价格超过阈值时通知多个订阅者(邮件、短信、 APP 推送)。

  3. 命令 + 备忘录:扩展文本编辑器的命令模式实现,添加宏录制功能——记录一系列命令并一次性回放。

  4. 状态模式:实现一个自动售货机状态机,包含状态:待投币、已投币、出货中、缺货。画出状态转换图并用代码实现。

  5. 责任链:为一个 Web API 实现中间件链: CORS → RateLimit → Auth → Validation → Handler → ErrorHandler 。测试不同请求场景下的链式处理行为。

  6. 迭代器:用生成器实现一个二叉树的中序遍历前序遍历层序遍历迭代器。

面试要点

Q1: 策略模式和状态模式有什么区别? A: 策略模式让客户端主动选择算法,策略之间互不感知;状态模式中状态对象知道其他状态,状态转换由内部自动完成。策略是"做什么"的选择,状态是"处于什么阶段"的管理。

Q2: 观察者模式在实际项目中怎么用? A: 最常见的是事件系统和发布-订阅。如:用户注册后发布事件,邮件服务、积分服务、数据统计服务各自订阅处理。 Django 的 Signal 、 Spring 的 ApplicationEvent 都是观察者模式的实现。

Q3: 什么场景下用命令模式? A: 需要将操作对象化的场景:(1)撤销/重做 (2)操作排队 (3)宏录制 (4)事务回滚 (5)远程操作。核心是把"做什么"封装成对象,与"谁来做"、"何时做"解耦。

Q4: 责任链模式在哪些框架中用到? A: Django Middleware 、 Express.js 的中间件、 Java Servlet Filter 、 Netty 的 ChannelPipeline 。请求沿链传递,每个节点决定处理或传给下一个。

自我检查清单

  • 能区分策略、状态、命令三者的意图
  • 能实现一个完整的观察者/事件系统
  • 理解 Python 的迭代器协议和生成器
  • 能用责任链实现中间件系统
  • 能解释模板方法和策略的选择依据
  • 至少完成 3 道练习题

下一章: 05-设计模式实战 — 在真实项目中综合运用设计模式

⚠️ 核验说明(2026-04-03):本页已按行为型模式的稳定概念复核。策略、观察者、命令、状态、责任链等模式在现代框架中经常以回调、事件系统、中间件或状态机库的形式出现,理解协作关系和状态流转比照抄模板更关键。


最后更新日期: 2026-04-03