学习指南
设计模式不是靠死记硬背掌握的,而是通过理解、实践和思考逐步建立的设计思维。本章为你提供高效学习设计模式的方法和技巧。
学习路径
graph LR
A[第1步
理解概念] --> B[第2步
查看示例] B --> C[第3步
动手实践] C --> D[第4步
分析应用场景] D --> E[第5步
应用到项目] E --> F[第6步
反思总结] A --> A1[模式解决的问题] B --> B1[标准实现方式] C --> C1[修改、扩展、重写] D --> D1[何时用、何时不该用] E --> E1[识别使用机会] F --> F1[记录笔记和心得] style A fill:#e3f2fd,stroke:#1976d2,stroke-width:2px style B fill:#e3f2fd,stroke:#1976d2,stroke-width:2px style C fill:#fff9c4,stroke:#f9a825,stroke-width:2px style D fill:#fff9c4,stroke:#f9a825,stroke-width:2px style E fill:#c8e6c9,stroke:#43a047,stroke-width:2px style F fill:#a5d6a7,stroke:#43a047,stroke-width:2px
理解概念] --> B[第2步
查看示例] B --> C[第3步
动手实践] C --> D[第4步
分析应用场景] D --> E[第5步
应用到项目] E --> F[第6步
反思总结] A --> A1[模式解决的问题] B --> B1[标准实现方式] C --> C1[修改、扩展、重写] D --> D1[何时用、何时不该用] E --> E1[识别使用机会] F --> F1[记录笔记和心得] style A fill:#e3f2fd,stroke:#1976d2,stroke-width:2px style B fill:#e3f2fd,stroke:#1976d2,stroke-width:2px style C fill:#fff9c4,stroke:#f9a825,stroke-width:2px style D fill:#fff9c4,stroke:#f9a825,stroke-width:2px style E fill:#c8e6c9,stroke:#43a047,stroke-width:2px style F fill:#a5d6a7,stroke:#43a047,stroke-width:2px
第一步:理解核心概念
问自己三个问题
学习每个设计模式时,都要问自己:
- 这个模式解决什么问题?
- 不使用这个模式会怎样?
- 这个模式的核心思想是什么?
示例:单例模式
| 问题 | 答案 |
|---|---|
| 解决什么问题? | 确保一个类只有一个实例,并提供全局访问点 |
| 不用会怎样? | 多个实例可能导致状态不一致、资源浪费 |
| 核心思想是什么? | 控制实例化过程,提供唯一访问方式 |
第二步:查看标准实现
代码示例
# 单例模式的标准实现
class Singleton:
_instance = None
def __new__(cls, *args, **kwargs):
if cls._instance is None:
cls._instance = super().__new__(cls)
return cls._instance
# 验证
s1 = Singleton()
s2 = Singleton()
print(s1 is s2) # True,两个变量指向同一个实例
类图理解
用类图或流程图帮助理解模式结构:
classDiagram
class Singleton {
-instance: Singleton
+getInstance() Singleton
}
note for Singleton "单例模式确保一个类只有一个实例"
第三步:动手实践
练习1:修改示例
# 练习:给单例模式添加初始化参数
class ConfigSingleton:
_instance = None
_initialized = False
def __new__(cls, *args, **kwargs):
if cls._instance is None:
cls._instance = super().__new__(cls)
return cls._instance
def __init__(self, config_file=None):
if not self._initialized:
self.config = {}
if config_file:
self.load_config(config_file)
self._initialized = True
def load_config(self, file):
self.config = {"from": file}
def get(self, key):
return self.config.get(key)
# 测试
config1 = ConfigSingleton("app.conf")
config2 = ConfigSingleton("another.conf") # 不会重新初始化
print(config1.get("from")) # app.conf
print(config2.get("from")) # app.conf(同一个实例)
练习2:识别模式
阅读现有代码,尝试识别使用了哪些设计模式:
# 这段代码用了什么模式?
from abc import ABC, abstractmethod
class SortStrategy(ABC):
@abstractmethod
def sort(self, data):
pass
class BubbleSort(SortStrategy):
def sort(self, data):
return sorted(data)
class QuickSort(SortStrategy):
def sort(self, data):
return sorted(data)
class Sorter:
def __init__(self, strategy: SortStrategy):
self.strategy = strategy
def perform_sort(self, data):
return self.strategy.sort(data)
答案:策略模式(Strategy Pattern)
第四步:分析应用场景
使用场景分析
| 场景 | 是否适合单例模式 | 理由 |
|---|---|---|
| 数据库连接池 | ✅ 适合 | 需要全局唯一,避免重复连接 |
| 工具类(如Math) | ❌ 不适合 | 可以用静态方法,无需实例 |
| 配置管理器 | ✅ 适合 | 需要全局唯一,缓存配置 |
| 日志记录器 | ✅ 适合 | 避免文件冲突,统一输出 |
反例:误用设计模式
# ❌ 误用单例模式
class Calculator:
_instance = None
def __new__(cls):
if cls._instance is None:
cls._instance = super().__new__(cls)
return cls._instance
def add(self, x, y):
return x + y
# 问题:Calculator根本不需要单例!
# 应该用普通类或静态方法
# ✅ 正确做法
class Calculator:
@staticmethod
def add(x, y):
return x + y
第五步:应用到项目
在实际代码中识别机会
当你遇到以下情况时,考虑使用设计模式:
| 问题信号 | 可能的设计模式 |
|---|---|
代码中大量 if-elif-else 或 switch-case | 策略模式、状态模式 |
| 需要在不修改原代码的情况下扩展功能 | 装饰器模式 |
| 对象创建逻辑复杂 | 工厂模式、建造者模式 |
| 多个类需要共享行为 | 模板方法模式 |
| 需要通知多个对象某个事件 | 观察者模式 |
重构示例
重构前:
class NotificationService:
"""通知服务 - 大量if-elif"""
def send(self, message, channel):
if channel == "email":
self._send_email(message)
elif channel == "sms":
self._send_sms(message)
elif channel == "push":
self._send_push(message)
elif channel == "wechat":
self._send_wechat(message)
# ... 更多类型
def _send_email(self, message):
print(f"邮件:{message}")
def _send_sms(self, message):
print(f"短信:{message}")
def _send_push(self, message):
print(f"推送:{message}")
def _send_wechat(self, message):
print(f"微信:{message}")
重构后(使用策略模式):
from abc import ABC, abstractmethod
class NotificationStrategy(ABC):
@abstractmethod
def send(self, message):
pass
class EmailNotification(NotificationStrategy):
def send(self, message):
print(f"邮件:{message}")
class SMSNotification(NotificationStrategy):
def send(self, message):
print(f"短信:{message}")
class PushNotification(NotificationStrategy):
def send(self, message):
print(f"推送:{message}")
class WeChatNotification(NotificationStrategy):
def send(self, message):
print(f"微信:{message}")
class NotificationService:
def __init__(self, strategy: NotificationStrategy):
self.strategy = strategy
def send(self, message):
self.strategy.send(message)
# 使用:轻松扩展新渠道
class SlackNotification(NotificationStrategy):
def send(self, message):
print(f"Slack:{message}")
email_service = NotificationService(EmailNotification())
slack_service = NotificationService(SlackNotification())
email_service.send("你好") # 邮件:你好
slack_service.send("你好") # Slack:你好
第六步:反思总结
学习笔记模板
为每个设计模式创建一份学习笔记:
# 模式名称
## 核心概念
- 这个模式解决什么问题?
- 核心思想是什么?
## 标准实现
[代码示例]
## 适用场景
- ✅ 场景1
- ✅ 场景2
## 不适用场景
- ❌ 场景1
- ❌ 场景2
## 实际应用
[在项目中应用的例子]
## 相关模式
- 与XX模式的区别
- 可以与XX模式组合使用
学习技巧
技巧1:对比学习
对比相似的模式,理解差异:
| 模式 | 目的 | 何时使用 |
|---|---|---|
| 工厂方法 | 创建对象 | 不知道具体类型 |
| 抽象工厂 | 创建对象族 | 需要创建相关对象 |
| 建造者 | 创建复杂对象 | 需要分步骤创建 |
| 原型 | 复制对象 | 创建成本高 |
技巧2:从简单开始
先用最简单的实现,理解核心思想:
# 单例模式 - 最简单版本
class Singleton:
instance = None
def get_instance():
if Singleton.instance is None:
Singleton.instance = Singleton()
return Singleton.instance
# 等理解了再加线程安全等其他考虑
技巧3:查看源码
学习Python标准库和框架中的模式应用:
# Python标准库中的设计模式
# 迭代器模式 - built-in
for item in [1, 2, 3]:
print(item)
# 装饰器模式 - @decorator语法
@log_calls
def my_function():
pass
# 单例模式 - sys.modules
import sys
sys.modules['my_module'] = my_module # 模块只加载一次
技巧4:画图理解
用图示帮助理解模式关系:
graph TB
A[创建型模式] --> B[单例]
A --> C[工厂方法]
A --> D[抽象工厂]
A --> E[建造者]
F[创建方式] --> G[简单对象]
F --> H[复杂对象]
F --> I[对象族]
G --> C
H --> E
I --> D
D --> B
style A fill:#ede7f6,stroke:#5e35b1,stroke-width:3px
常见错误
❌ 错误1:过度设计
# 为了用模式而用模式
class SimpleCalculator:
def calculate(self, operation, x, y):
if operation == "add":
return x + y
elif operation == "subtract":
return x - y
# 不要用策略模式重构!简单直接更好
❌ 错误2:死记硬背
不要只记住代码实现,要理解原理。
错误做法: - 背诵单例模式的代码 - 背诵UML类图
正确做法: - 理解单例模式解决的问题 - 知道何时使用单例模式 - 能自己推导出实现方式
❌ 错误3:忽视语言特性
Python有独特的语法糖,可以简化模式实现:
# 传统装饰器模式
class LoggingDecorator:
def __init__(self, component):
self.component = component
def operation(self):
print("开始执行")
result = self.component.operation()
print("执行完成")
return result
# Python方式:装饰器语法
@log_calls
def operation():
pass
学习资源
推荐书籍
-
《设计模式:可复用面向对象软件的基础》(GoF四人组) - 设计模式的圣经 - 23种经典模式
-
《Head First 设计模式》 - 适合初学者 - 图文并茂,生动有趣
-
《Python设计模式》 - Python-specific - 实用性强
推荐网站
- Refactoring Guru:https://refactoring.guru/
- 每个模式都有图解和代码
-
多语言支持
-
Source Making:https://sourcemaking.com/
- 深入的模式讨论
- 反模式分析
学习计划
基础阶段(第1-2周)
- 阅读本书前4章
- 理解15种核心模式
- 运行所有代码示例
进阶阶段(第3-4周)
- 完成章节练习
- 重构一个小项目
- 阅读推荐资源
实践阶段(第5-6周)
- 在项目中应用模式
- 分析开源项目代码
- 写学习博客
本章要点
- ✅ 设计模式不是靠背诵,靠理解和实践
- ✅ 每个模式问三个问题:解决什么?不用会怎样?核心思想?
- ✅ 动手实践:修改、扩展、重写示例代码
- ✅ 识别模式在现有代码中的应用
- ✅ 在实际项目中寻找应用机会
- ✅ 避免过度设计,不要为了用模式而用模式
- ✅ 利用Python语言特性简化模式实现
- ✅ 持续学习,建立自己的模式知识库
恭喜完成前置知识部分!
下一步:创建型模式 开始学习第一个设计模式 🚀