Loading

【设计模式与重构】设计模式

设计模式

发布时间:2020-12-25 00:40:00
原文链接:https://www.cnblogs.com/xine/p/14187051
结构图来源:refactoringguru.cn

设计模式(Design Pattern)是前人在大量软件实践中总结出的、可复用的面向对象设计方案。GoF(Gang of Four)在《设计模式:可复用面向对象软件的基础》一书中归纳了 23 个经典模式,按目的分为三大类:创建型、结构型、行为型。本文用 Python 逐一梳理这 22 个模式(Interpreter 不在 refactoringguru 收录范围内,故略),每个模式配一张 UML 结构图。

一、概述

类别 关注点 模式
创建型 对象怎么"造"出来 单例、原型、工厂方法、抽象工厂、建造者
结构型 类和对象怎么"组装" 适配器、桥接、组合、装饰器、外观、享元、代理
行为型 对象之间怎么"协作" 责任链、命令、迭代器、中介者、备忘录、观察者、状态、策略、模板方法、访问者

两条基本原则贯穿始终:面向接口编程,而不是面向实现编程;优先使用组合,而不是继承。

二、创建型模式

创建型模式把对象的创建过程封装起来,让程序在"谁来创建、创建什么、何时创建"上保持灵活。

2.1 单例模式(Singleton)

意图:保证一个类只有一个实例,并提供全局访问点。典型场景:配置管理器、连接池、日志对象。

单例模式结构图

Python 里最优雅的写法是借助模块天然的单例性,或用 __new__ 控制:

class Singleton:
    _instance = None

    def __new__(cls, *args, **kwargs):
        if cls._instance is None:
            cls._instance = super().__new__(cls)
        return cls._instance


a = Singleton()
b = Singleton()
print(a is b)  # True

线程安全版本可以加锁:

import threading

class ThreadSafeSingleton:
    _instance = None
    _lock = threading.Lock()

    def __new__(cls):
        with cls._lock:
            if cls._instance is None:
                cls._instance = super().__new__(cls)
        return cls._instance

注意:单例本质上是"全局状态",测试和并发场景要慎用,Python 中更推荐直接用模块级对象。

2.2 原型模式(Prototype)

意图:通过克隆已有实例来创建新对象,避免重复的初始化开销,或实现"快照"能力。

原型模式结构图

import copy

class Prototype:
    def clone(self):
        return copy.deepcopy(self)

    def __init__(self, name, tags=None):
        self.name = name
        self.tags = tags if tags is not None else []


proto = Prototype("模板", tags=["a", "b"])
shallow = copy.copy(proto)    # 浅拷贝:共享内部列表
deep = proto.clone()          # 深拷贝:完全独立

deep.tags.append("c")
print(proto.tags)  # ['a', 'b'],不受影响

适用场景:对象创建代价大(数据库/网络初始化);需要保存对象某一时刻的状态(如编辑器的撤销快照)。注意区分浅拷贝与深拷贝。

2.3 工厂方法模式(Factory Method)

意图:定义创建对象的接口,让子类决定实例化哪个具体类。把 new 的决定权从使用方移到子类。

工厂方法模式结构图

from abc import ABC, abstractmethod


class Transport(ABC):
    @abstractmethod
    def deliver(self, cargo: str) -> str: ...


class Truck(Transport):
    def deliver(self, cargo: str) -> str:
        return f"陆运:{cargo} 装上卡车出发"


class Ship(Transport):
    def deliver(self, cargo: str) -> str:
        return f"海运:{cargo} 装上货轮出发"


class Logistics(ABC):                    # Creator
    @abstractmethod
    def create_transport(self) -> Transport:  # 工厂方法
        ...

    def plan_delivery(self, cargo: str) -> str:
        transport = self.create_transport()
        return transport.deliver(cargo)


class RoadLogistics(Logistics):          # ConcreteCreator
    def create_transport(self) -> Transport:
        return Truck()


class SeaLogistics(Logistics):
    def create_transport(self) -> Transport:
        return Ship()


print(RoadLogistics().plan_delivery("钢琴"))
print(SeaLogistics().plan_delivery("钢琴"))

核心收益:新增一种运输方式时,只需新增一对类,原有代码(plan_delivery)一行不用改,符合开闭原则。

2.4 抽象工厂模式(Abstract Factory)

意图:创建一族相关的产品对象,而不指定具体类。工厂方法针对"一个产品",抽象工厂针对"一组产品"。

抽象工厂模式结构图

from abc import ABC, abstractmethod


# 抽象产品:按钮 和 复选框
class Button(ABC):
    @abstractmethod
    def paint(self) -> str: ...


class Checkbox(ABC):
    @abstractmethod
    def paint(self) -> str: ...


# Win 家族
class WinButton(Button):
    def paint(self) -> str:
        return "Windows 风格按钮"


class WinCheckbox(Checkbox):
    def paint(self) -> str:
        return "Windows 风格复选框"


# Mac 家族
class MacButton(Button):
    def paint(self) -> str:
        return "Mac 风格按钮"


class MacCheckbox(Checkbox):
    def paint(self) -> str:
        return "Mac 风格复选框"


# 抽象工厂:一次生产一整族 UI 组件
class GUIFactory(ABC):
    @abstractmethod
    def create_button(self) -> Button: ...

    @abstractmethod
    def create_checkbox(self) -> Checkbox: ...


class WinFactory(GUIFactory):
    def create_button(self) -> Button:
        return WinButton()

    def create_checkbox(self) -> Checkbox:
        return WinCheckbox()


class MacFactory(GUIFactory):
    def create_button(self) -> Button:
        return MacButton()

    def create_checkbox(self) -> Checkbox:
        return MacCheckbox()


class Application:
    def __init__(self, factory: GUIFactory):
        self.factory = factory

    def render(self):
        button = self.factory.create_button()
        checkbox = self.factory.create_checkbox()
        print(button.paint(), "|", checkbox.paint())


Application(MacFactory()).render()  # Mac 风格按钮 | Mac 风格复选框

适用场景:系统要支持多个"产品族"(Win/Mac、浅色/深色主题、MySQL/PG 驱动组),且要求族内产品搭配使用。缺点是新增产品种类(不只是族)时要改所有工厂接口。

2.5 建造者模式(Builder)

意图:分步骤构造复杂对象,使"构建过程"与"表示"分离。当构造函数参数多、可选参数杂( telescoping constructor 噩梦)时尤其有用。

建造者模式结构图

class Computer:
    def __init__(self):
        self.cpu = None
        self.memory = None
        self.disk = None
        self.gpu = None          # 可选

    def __str__(self):
        parts = [self.cpu, self.memory, self.disk, self.gpu]
        return "Computer(" + ", ".join(p for p in parts if p) + ")"


class ComputerBuilder:
    def __init__(self):
        self._product = Computer()

    def cpu(self, value):
        self._product.cpu = value
        return self              # 支持链式调用

    def memory(self, value):
        self._product.memory = value
        return self

    def disk(self, value):
        self._product.disk = value
        return self

    def gpu(self, value):
        self._product.gpu = value
        return self

    def build(self) -> Computer:
        if not self._product.cpu or not self._product.memory:
            raise ValueError("CPU 和内存为必选组件")
        product, self._product = self._product, Computer()
        return product


pc = (ComputerBuilder()
      .cpu("i9-14900K")
      .memory("64G DDR5")
      .disk("2T NVMe")
      .gpu("RTX 4090")
      .build())
print(pc)  # Computer(i9-14900K, 64G DDR5, 2T NVMe, RTX 4090)

对比工厂模式:工厂关心"造什么",建造者关心"怎么一步步组装"。Python 中 dataclasses + 关键字参数也能缓解构造参数问题,但建造者仍适合有"组装顺序/校验规则"的场景。

三、结构型模式

结构型模式解决"如何把类和对象组合成更大的结构,同时保持灵活高效"。

3.1 适配器模式(Adapter)

意图:把一个类的接口转换成客户端期望的另一个接口,让不兼容的类可以合作。典型的"转接头"。

适配器模式结构图

class LegacyPayment:                 # 遗留接口
    def make_payment(self, amount_in_cents: int):
        print(f"遗留系统支付 {amount_in_cents} 分")


class ModernPaymentGateway:          # 新代码期望的接口
    def pay(self, amount_yuan: float):
        pass


class PaymentAdapter(ModernPaymentGateway):
    def __init__(self, legacy: LegacyPayment):
        self.legacy = legacy

    def pay(self, amount_yuan: float):   # 接口转换 + 单位转换
        self.legacy.make_payment(int(amount_yuan * 100))


gateway = PaymentAdapter(LegacyPayment())
gateway.pay(9.9)  # 遗留系统支付 990 分

3.2 桥接模式(Bridge)

意图:把"抽象"和"实现"放在两个独立的维度上分别继承/组合,避免类爆炸(如 形状×渲染方式 的笛卡尔积)。

桥接模式结构图

from abc import ABC, abstractmethod


class Renderer(ABC):                 # 实现维度
    @abstractmethod
    def render_circle(self, radius: float): ...


class VectorRenderer(Renderer):
    def render_circle(self, radius: float):
        print(f"画矢量圆,半径 {radius}")


class RasterRenderer(Renderer):
    def render_circle(self, radius: float):
        print(f"逐像素画圆,半径 {radius}")


class Shape(ABC):                    # 抽象维度,持有实现引用(桥)
    def __init__(self, renderer: Renderer):
        self.renderer = renderer

    @abstractmethod
    def draw(self): ...


class Circle(Shape):
    def __init__(self, renderer: Renderer, radius: float):
        super().__init__(renderer)
        self.radius = radius

    def draw(self):
        self.renderer.render_circle(self.radius)


Circle(VectorRenderer(), 5).draw()   # 画矢量圆,半径 5
Circle(RasterRenderer(), 5).draw()   # 逐像素画圆,半径 5

新增形状或新增渲染器,各自扩展即可,2×N 的组合不再需要 N 倍的子类。

3.3 组合模式(Composite)

意图:把对象组成树形结构,让客户端用统一的方式处理单个对象和对象容器。文件系统是最典型的例子。

组合模式结构图

from abc import ABC, abstractmethod


class Component(ABC):
    @abstractmethod
    def size(self) -> int: ...


class File(Component):               # 叶子节点
    def __init__(self, name: str, size: int):
        self.name = name
        self.size_ = size

    def size(self) -> int:
        return self.size_


class Folder(Component):             # 容器节点
    def __init__(self, name: str):
        self.name = name
        self.children = []

    def add(self, component: Component):
        self.children.append(component)

    def size(self) -> int:
        return sum(c.size() for c in self.children)


root = Folder("root")
src = Folder("src")
src.add(File("main.py", 10))
src.add(File("utils.py", 5))
root.add(src)
root.add(File("README.md", 1))
print(root.size())  # 16,整棵树自动递归求和

3.4 装饰器模式(Decorator)

意图:不修改原类的前提下,动态给对象叠加新职责。Python 的 @decorator 语法糖名字来源于此思想,但两者并不等价。

装饰器模式结构图

from abc import ABC, abstractmethod


class DataSource(ABC):
    @abstractmethod
    def write(self, data: str): ...


class FileDataSource(DataSource):    # 被装饰的核心对象
    def __init__(self, filename: str):
        self.filename = filename

    def write(self, data: str):
        print(f"写入 {self.filename}: {data!r}")


class DataSourceDecorator(DataSource):   # 装饰器基类,同接口
    def __init__(self, wrappee: DataSource):
        self.wrappee = wrappee

    def write(self, data: str):
        self.wrappee.write(data)


class CompressDecorator(DataSourceDecorator):
    def write(self, data: str):
        print("[先压缩]")
        self.wrappee.write(data)


class EncryptDecorator(DataSourceDecorator):
    def write(self, data: str):
        self.wrappee.write(data[::-1])   # 简单示意:倒序=加密


file = FileDataSource("data.txt")
stream = EncryptDecorator(CompressDecorator(file))
stream.write("hello")
# [先压缩]
# 写入 data.txt: 'olleh'

装饰器可以像洋葱一样层层叠加,比"为每种组合建一个子类"灵活得多。

3.5 外观模式(Facade)

意图:为复杂子系统提供一个简化的统一入口。它不是加功能,而是"减负"。

外观模式结构图

class CPU:
    def freeze(self): print("CPU 冻结")
    def jump(self, addr): print(f"CPU 跳转到 {addr:#x}")
    def execute(self): print("CPU 执行")


class Memory:
    def load(self, data): print("内存加载数据")


class Disk:
    def read(self, sector): print(f"磁盘读取扇区 {sector}")


class ComputerFacade:                # 一行代码开机
    def __init__(self):
        self.cpu, self.memory, self.disk = CPU(), Memory(), Disk()

    def start(self):
        self.cpu.freeze()
        self.memory.load(self.disk.read(0))
        self.cpu.jump(0)
        self.cpu.execute()


ComputerFacade().start()

3.6 享元模式(Flyweight)

意图:共享大量细粒度对象的公共状态,用极小的内存表示海量对象。核心是分离内部状态(可共享)与外部状态(不可共享)。

享元模式结构图

class TreeType:                      # 享元:内部状态(种类、颜色、纹理)
    def __init__(self, name, color, texture):
        self.name, self.color, self.texture = name, color, texture

    def draw(self, x, y):            # 外部状态由调用方传入
        print(f"{self.color}的{self.name} 画在 ({x},{y})")


class TreeFactory:
    _types = {}

    @classmethod
    def get_tree_type(cls, name, color, texture):
        key = (name, color, texture)
        if key not in cls._types:
            cls._types[key] = TreeType(name, color, texture)
        return cls._types[key]


class Forest:
    def __init__(self):
        self.trees = []              # (treeType, x, y)

    def plant(self, name, color, texture, x, y):
        ttype = TreeFactory.get_tree_type(name, color, texture)
        self.trees.append((ttype, x, y))

    def draw(self):
        for ttype, x, y in self.trees:
            ttype.draw(x, y)


forest = Forest()
for i in range(10000):               # 10000 棵树只共享少数几个 TreeType
    forest.plant("松树", "深绿", "针叶纹理", i % 100, i // 100)

Python 中 sys.intern、字符串驻留、__slots__ 都是这种"省内存"思想的体现。

3.7 代理模式(Proxy)

意图:提供一个与原对象同接口的"替身",在访问前后插入控制逻辑:延迟加载、权限校验、缓存、远程调用等。

代理模式结构图

import time


class HeavyService:
    def __init__(self):
        time.sleep(2)                # 模拟昂贵的初始化
        print("真实服务初始化完成")

    def request(self):
        return "真实响应"


class LazyProxy:                     # 虚代理:用到才加载
    def __init__(self):
        self._service = None

    def request(self):
        if self._service is None:
            self._service = HeavyService()
        return self._service.request()


proxy = LazyProxy()
print("代理已创建,但服务还没初始化")
print(proxy.request())               # 此刻才真正初始化
print(proxy.request())               # 第二次直接复用

与装饰器的区别:装饰器叠加以增强行为,代理控制对目标的访问;二者结构相同,意图不同。

四、行为型模式

行为型模式关注对象间的职责分配与通信方式。

4.1 责任链模式(Chain of Responsibility)

意图:让多个处理器组成一条链,请求沿链传递,每个处理器决定"处理它"或"传给下一个"。Web 中间件、审批流都是它。

责任链模式结构图

from abc import ABC, abstractmethod


class Handler(ABC):
    def __init__(self, next=None):
        self.next = next

    def handle(self, request: str):
        if self.can_handle(request):
            self.do_handle(request)
        elif self.next:
            self.next.handle(request)
        else:
            print(f"没人能处理请求:{request}")

    @abstractmethod
    def can_handle(self, request: str) -> bool: ...

    @abstractmethod
    def do_handle(self, request: str): ...


class MonkeyHandler(Handler):
    def can_handle(self, r): return r == "香蕉"

    def do_handle(self, r): print("猴子处理了香蕉")


class DogHandler(Handler):
    def can_handle(self, r): return r == "骨头"

    def do_handle(self, r): print("狗处理了骨头")


chain = MonkeyHandler(DogHandler())
chain.handle("香蕉")   # 猴子处理了香蕉
chain.handle("骨头")   # 狗处理了骨头
chain.handle("鱼")     # 没人能处理请求:鱼

4.2 命令模式(Command)

意图:把"请求"封装成对象,从而支持排队、日志、撤销/重做。GUI 按钮、编辑器撤销栈的核心模式。

命令模式结构图

from abc import ABC, abstractmethod


class Command(ABC):
    @abstractmethod
    def execute(self): ...

    def undo(self): ...


class Editor:
    def __init__(self):
        self.text = ""

    def insert(self, s): self.text += s
    def delete(self, n): self.text = self.text[:-n]


class InsertCommand(Command):
    def __init__(self, editor: Editor, s: str):
        self.editor, self.s = editor, s

    def execute(self):
        self.editor.insert(self.s)

    def undo(self):
        self.editor.delete(len(self.s))


class History:                       # 调用者:只认识 Command
    def __init__(self):
        self.stack = []

    def run(self, cmd: Command):
        cmd.execute()
        self.stack.append(cmd)

    def undo(self):
        if self.stack:
            self.stack.pop().undo()


editor, history = Editor(), History()
history.run(InsertCommand(editor, "hello "))
history.run(InsertCommand(editor, "world"))
print(editor.text)     # hello world
history.undo()
print(editor.text)     # hello

在 Python 中,一个带 __call__ 的闭包类或函数对象同样可以充当命令。

4.3 迭代器模式(Iterator)

意图:顺序遍历集合元素,而不暴露集合的内部表示。Python 把它做成了语言级协议:__iter__ / __next__(以及 for 循环、生成器)。

迭代器模式结构图

class BinaryTree:
    def __init__(self, value, left=None, right=None):
        self.value, self.left, self.right = value, left, right

    def __iter__(self):
        """中序遍历——用生成器实现迭代器,最 Pythonic 的方式"""
        if self.left:
            yield from self.left
        yield self.value
        if self.right:
            yield from self.right


tree = BinaryTree(2,
    left=BinaryTree(1),
    right=BinaryTree(3))

for v in tree:            # 集合内部是树,客户端却像遍历列表一样简单
    print(v, end=" ")     # 1 2 3

4.4 中介者模式(Mediator)

意图:把网状的对象互调收敛为"都只跟中介说话",减少对象间的耦合。聊天室、机场塔台、MVC 中的 Controller。

中介者模式结构图

from abc import ABC, abstractmethod


class ChatRoom:                      # 中介者
    def __init__(self):
        self.users = []

    def register(self, user):
        self.users.append(user)
        user.room = self

    def broadcast(self, sender, message: str):
        for u in self.users:
            if u is not sender:
                u.receive(f"[{sender.name}] {message}")


class User:                          # 同事类:只认识中介
    def __init__(self, name: str):
        self.name = name
        self.room = None

    def send(self, message: str):
        self.room.broadcast(self, message)

    def receive(self, message: str):
        print(f"{self.name} 收到:{message}")


room = ChatRoom()
alice, bob = User("Alice"), User("Bob")
room.register(alice)
room.register(bob)
alice.send("大家好")   # Bob 收到:[Alice] 大家好

4.5 备忘录模式(Memento)

意图:在不破坏封装的前提下,捕获对象内部状态并存档,以便之后恢复。与命令模式配合可实现完整的撤销体系。

备忘录模式结构图

from dataclasses import dataclass


@dataclass(frozen=True)             # 不可变快照
class Memento:
    state: str


class Originator:                    # 原发器
    def __init__(self, state: str):
        self._state = state

    def do(self, action: str):
        self._state += action

    def save(self) -> Memento:
        return Memento(self._state)

    def restore(self, memento: Memento):
        self._state = memento.state

    def __str__(self):
        return self._state


class Caretaker:                     # 管理者:只存快照,不看不改
    def __init__(self):
        self._history = []

    def backup(self, memento: Memento):
        self._history.append(memento)

    def undo(self) -> Memento:
        return self._history.pop()


doc = Originator("第一章")
history = Caretaker()
history.backup(doc.save())
doc.do(",第二节")
history.backup(doc.save())
doc.do(",第三节")
print(doc)                 # 第一章,第二节,第三节
doc.restore(history.undo())
print(doc)                 # 第一章,第二节

4.6 观察者模式(Observer)

意图:定义一对多的订阅关系,状态变化时自动通知所有订阅者。事件系统、消息队列、MVVM 数据绑定的基石。

观察者模式结构图

class Event:
    """极简事件总线:任何人可订阅,发布时全部回调"""

    def __init__(self):
        self._subscribers = []

    def subscribe(self, callback):
        self._subscribers.append(callback)

    def publish(self, data):
        for callback in self._subscribers:
            callback(data)


class PriceTicker:
    def __init__(self):
        self.price_changed = Event()

    def set_price(self, new_price: float):
        self.price_changed.publish(new_price)


ticker = PriceTicker()
ticker.price_changed.subscribe(lambda p: print(f"短信通知:价格变为 {p}"))
ticker.price_changed.subscribe(lambda p: print(f"图表刷新:{p:.2f}"))
ticker.set_price(102.5)
# 短信通知:价格变为 102.5
# 图表刷新:102.50

4.7 状态模式(State)

意图:把"某状态下的一整套行为"封装成状态类,用替换状态对象代替大量的 if/elif 状态判断。

状态模式结构图

from abc import ABC, abstractmethod


class State(ABC):
    @abstractmethod
    def play(self, player) -> str: ...

    @abstractmethod
    def pause(self, player) -> str: ...


class PlayingState(State):
    def play(self, player): return "已在播放中"
    def pause(self, player):
        player.state = PausedState()
        return "暂停播放"


class PausedState(State):
    def play(self, player):
        player.state = PlayingState()
        return "继续播放"
    def pause(self, player): return "已处于暂停"


class LockedState(State):
    def play(self, player): return "先解锁再操作"
    def pause(self, player): return "先解锁再操作"


class AudioPlayer:
    def __init__(self):
        self.state = LockedState()

    def click_play(self):  return self.state.play(self)
    def click_pause(self): return self.state.pause(self)

    def unlock(self):
        self.state = PausedState()
        return "解锁"


player = AudioPlayer()
print(player.click_play())   # 先解锁再操作
player.unlock()
print(player.click_play())   # 继续播放
print(player.click_pause())  # 暂停播放

4.8 策略模式(Strategy)

意图:定义一族可互换的算法,运行时按需切换,消除大量条件分支。

策略模式结构图

from abc import ABC, abstractmethod


class DiscountStrategy(ABC):
    @abstractmethod
    def apply(self, price: float) -> float: ...


class NoDiscount(DiscountStrategy):
    def apply(self, price): return price


class HalfPrice(DiscountStrategy):
    def apply(self, price): return price * 0.5


class FullReduction(DiscountStrategy):      # 满100减30
    def apply(self, price):
        return price - (price // 100) * 30


class Order:
    def __init__(self, price: float, strategy: DiscountStrategy):
        self.price = price
        self.strategy = strategy

    def checkout(self) -> float:
        return self.strategy.apply(self.price)


print(Order(250, FullReduction()).checkout())  # 160.0
print(Order(250, HalfPrice()).checkout())      # 125.0

Python 里策略还可以直接用函数传递——比类更轻量,但需要"一组有共享上下文的策略"时,类形式更整洁。

4.9 模板方法模式(Template Method)

意图:父类定义算法骨架(固定步骤顺序),把某些步骤延迟到子类实现。数据管道、测试框架 setUp/run/tearDown 的套路。

模板方法模式结构图

from abc import ABC, abstractmethod


class DataPipeline(ABC):
    def run(self):                       # 模板方法:固定流程
        raw = self.extract()
        cleaned = self.transform(raw)
        self.load(cleaned)
        print("流水线执行完毕\n")

    @abstractmethod
    def extract(self): ...               # 子类必须实现

    @abstractmethod
    def transform(self, data): ...

    def load(self, data):                # 钩子:可选覆盖
        print(f"写入目标:{data}")


class EtlCsv(DataPipeline):
    def extract(self): return "csv原始数据"
    def transform(self, data): return data.upper()


class EtlApi(DataPipeline):
    def extract(self): return "api的json"
    def transform(self, data): return data + "(已校验)"
    def load(self, data):                # 自定义加载
        print(f"POST 写入远程:{data}")


EtlCsv().run()
EtlApi().run()

4.10 访问者模式(Visitor)

意图:在不修改对象结构的前提下,为结构中的元素添加新操作。把"数据结构"和"作用于结构的算法"分开(双分派)。

访问者模式结构图

from abc import ABC, abstractmethod


class Visitor(ABC):
    @abstractmethod
    def visit_circle(self, circle): ...

    @abstractmethod
    def visit_square(self, square): ...


class Shape(ABC):
    @abstractmethod
    def accept(self, visitor: Visitor): ...


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

    def accept(self, visitor):
        visitor.visit_circle(self)      # 第一次分派


class Square(Shape):
    def __init__(self, side): self.side = side

    def accept(self, visitor):
        visitor.visit_square(self)


class AreaVisitor(Visitor):             # 新操作一:算面积
    def visit_circle(self, c): return 3.14159 * c.radius ** 2
    def visit_square(self, s): return s.side ** 2


class ExportVisitor(Visitor):           # 新操作二:导出 JSON,无需改 Shape
    def visit_circle(self, c): return f'{{"shape":"circle","r":{c.radius}}}'
    def visit_square(self, s): return f'{{"shape":"square","a":{s.side}}}'


shapes = [Circle(2), Square(3)]
print([s.accept(AreaVisitor()) for s in shapes])
print([s.accept(ExportVisitor()) for s in shapes])

编译器 AST 处理是访问者模式最经典的应用场景。

五、总结:如何选择

  1. 创建对象很麻烦 → 先想工厂方法/抽象工厂;参数太多用建造者;要复制已有对象用原型;全局唯一用单例。
  2. 想给对象加功能/控制访问 → 叠加职责用装饰器;接口不兼容用适配器;延迟加载、权限用代理;简化子系统用外观。
  3. 对象间在"打胶" → 一对多通知用观察者;请求处理链用责任链;撤销/重做用命令+备忘录;消灭 if/elif 分支用策略或状态。
  4. 慎用模式:模式是应对变化的工具,没有变化就别提前设计。过度设计比没有设计更可怕——"简单直接"往往才是最好的方案。
posted @ 2026-09-22 01:17  Stellan7  阅读(10)  评论(0)    收藏  举报