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 著。

浙公网安备 33010602011771号