GoF《设计模式》读后:一本"看不懂"但值得看两遍的书

先坦白一件事

第一次翻《设计模式:可复用面向对象软件的基础》是大二上学期。翻开目录看到 23 种模式密密麻麻列了一页,心想:这不得啃一个月?

结果第一章没读完就放弃了。

原因很简单:那时候我写的代码基本不超过 500 行,一个文件搞定所有逻辑,完全感觉不到"设计模式"跟我有什么关系。书里的例子都是 Smalltalk 和 C++,看着费劲。

大三这一年,接了几个正经项目——ERP 系统、数字人导游、库存管理——代码量上来之后,才慢慢回过头重新读。这次不一样了,因为我实实在在踩过坑。

这本书到底在讲什么

GoF(Gang of Four,四位作者)的核心观点是:软件设计中,大部分问题不是全新的。同样的结构在不同项目里反复出现,把这些问题和解决方案提炼出来,就是"设计模式"。

书中定义了 23 种模式,分为三大类:

类别 核心思想 典型模式
创建型 控制对象创建 单例、工厂、建造者
结构型 组织类与对象的组合 适配器、装饰器、代理
行为型 管理对象间的通信 观察者、策略、模板方法

每一种模式都遵循固定格式:意图 → 动机 → 结构 → 代码。这个结构化的描述方式本身就是一种思维的训练。

三个让我"恍然大悟"的模式

1. 策略模式:别再用 if-else 堆业务逻辑了

ERP 系统里有个场景:订单有不同的折扣计算方式——普通用户折扣、VIP 折扣、满减、优惠券……最开始我是这么写的:

def calculate_discount(order, user):
    if order.amount > 200:
        discount = order.amount * 0.1
    elif user.is_vip:
        discount = order.amount * 0.15
    elif user.has_coupon:
        discount = user.coupon_value
    else:
        discount = 0
    return discount

后来促销规则越加越多,这段代码膨胀到 80 行,每次加新规则都胆战心惊——改一处会不会影响别的?

读完策略模式,重构了一版:

from abc import ABC, abstractmethod

class DiscountStrategy(ABC):
    @abstractmethod
    def calculate(self, order, user) -> float:
        pass

class FullReductionDiscount(DiscountStrategy):
    def calculate(self, order, user):
        return order.amount * 0.1 if order.amount > 200 else 0

class VipDiscount(DiscountStrategy):
    def calculate(self, order, user):
        return order.amount * 0.15 if user.is_vip else 0

class CouponDiscount(DiscountStrategy):
    def calculate(self, order, user):
        return user.coupon_value if user.has_coupon else 0

class OrderCalculator:
    def __init__(self):
        self.strategies: list[DiscountStrategy] = []

    def add_strategy(self, strategy: DiscountStrategy):
        self.strategies.append(strategy)

    def calculate(self, order, user):
        return sum(s.calculate(order, user) for s in self.strategies)

加新规则?写一个新类,注册进去就完了。改现有规则?只改对应的类,别的完全不动。这就是"对扩展开放,对修改关闭"的感觉。

2. 观察者模式:解耦消息通知

灵山胜境项目里有个需求:导游回答完问题后,要同时做三件事——把对话存数据库、推 WebSocket 给前端、分析用户意图做推荐。

不用观察者模式的话,核心逻辑里塞满了这三件事的调用。用了之后:

class TourGuide:
    def __init__(self):
        self._observers = []

    def attach(self, observer):
        self._observers.append(observer)

    def notify(self, message):
        for observer in self._observers:
            observer.update(message)

class ConversationLogger:
    def update(self, message):
        db.save(message)  # 存数据库

class WebSocketNotifier:
    def update(self, message):
        ws.send(message)  # 推前端

class IntentAnalyzer:
    def update(self, message):
        self.analyze(message)  # 分析意图

核心导游逻辑完全不知道有哪些"后续处理",哪天要加一个消息队列推送,注册一个新 Observer 就行。这就是"分离关注点"在代码层面的体现。

3. 单例模式:用对是利器,用错是祸害

坦白说这是我用得最多的模式,但也最容易用错。

数据库连接池、配置管理器、日志器——这些全局只需要一个实例的东西,单例很合适。但大二的时候我什么都想搞成单例,连用户对象都是单例,结果测试的时候哭都来不及——全局状态让单元测试变得几乎不可能。

现在我的原则是:只有"无状态的、管理类型"的对象才用单例。业务数据对象绝对不要。

class ConfigManager:
    _instance = None

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

    def __init__(self):
        if not hasattr(self, '_initialized'):
            self.config = self._load_config()
            self._initialized = True

读这本书的正确姿势

经历了两遍阅读,我个人觉得这样读效果最好:

第一遍:遇到问题再翻。 不要从头到尾啃。代码里感觉"这块写得有点别扭"的时候去翻书,看看有没有对应的模式。这时候你带着真实的痛点和上下文,理解起来完全不一样。

第二遍:泛读建立连接。 把每种模式的意图和结构过一遍,不要求全记住,但要知道"有这个东西存在"。下次遇到类似问题时,脑子里能浮现一个模糊的印象,再去查细节。

另外,不要刻意套模式。为用一个模式而写代码是本末倒置。正路是:先写出能跑的代码,然后看看有没有可以用模式优化的地方。

这本书的局限

实事求是地说,这本书有些内容确实过时了:

  • 代码例子是 Smalltalk 和 C++,对 Python/JavaScript 开发者不够友好
  • 有些模式(如访问者模式、备忘录模式)在现代语言里已经被语法特性取代
  • 函数式编程大行其道的今天,很多模式的"面向对象"前提不再那么绝对

所以建议搭配一本更现代的书看,比如 Head First 设计模式 或者网上找对应语言的模式实现,会友好很多。

最后

读《设计模式》最大的收获不是记住了几种模式,而是建立了一种意识:代码的结构是可以被设计的,而不是不小心长成那样的。

当你开始思考"这段代码的职责边界在哪里"、"这个模块对外暴露什么接口"、"修改一个功能需要动几个文件"——这些问题的答案,往往就藏在设计模式里。

这不是一本读一遍就能放下的书。它更像一本词典:刚入门时看不懂,写了几万行代码后觉得有点意思,再写几万行回来翻,每次都有新发现。


GoF《设计模式:可复用面向对象软件的基础》,Erich Gamma / Richard Helm / Ralph Johnson / John Vlissides 著。

posted @ 2026-07-02 15:12  C(5,3)  阅读(6)  评论(0)    收藏  举报