设计模式是软件工程中经过验证的、可复用的解决方案,用于解决特定上下文中反复出现的设计问题。掌握设计模式能帮助你编写更优雅、可维护、可扩展的代码。本文将以Python为例,从基础概念到高级应用,详细讲解15种常用设计模式。每种模式均包含定义 、问题场景 、解决方案 、代码示例(带输出) 、优缺点 及适用场景。所有代码均可复制到本地运行,助你彻底理解设计模式的精髓。
目录
-
设计模式简介
-
创建型模式
-
单例模式(Singleton)
-
工厂方法模式(Factory Method)
-
抽象工厂模式(Abstract Factory)
-
建造者模式(Builder)
-
-
结构型模式
-
适配器模式(Adapter)
-
装饰器模式(Decorator)
-
代理模式(Proxy)
-
外观模式(Facade)
-
-
行为型模式
-
观察者模式(Observer)
-
策略模式(Strategy)
-
模板方法模式(Template Method)
-
状态模式(State)
-
责任链模式(Chain of Responsibility)
-
-
总结与下载说明
1. 设计模式简介
设计模式主要分为三大类:
-
创建型模式:对象实例化机制,如单例、工厂等。
-
结构型模式:组合类或对象以形成更大结构,如适配器、装饰器等。
-
行为型模式:对象之间的职责分配和通信,如观察者、策略等。
Python作为动态语言,部分模式实现更简洁(例如装饰器内置支持),但理解其背后的思想依然至关重要。
2. 创建型模式
2.1 单例模式(Singleton)
定义:确保一个类只有一个实例,并提供全局访问点。
问题场景:配置文件管理、数据库连接池、日志记录器等对象只需一个全局实例时。
解决方案 :通过重写__new__方法或使用元类控制实例创建。
代码示例:
bash
class Singleton:
"""经典单例实现"""
_instance = None
def __new__(cls, *args, **kwargs):
if cls._instance is None:
print("创建第一个实例")
cls._instance = super().__new__(cls)
else:
print("返回已存在的实例")
return cls._instance
def __init__(self, value=None):
# 注意:__init__每次都会执行,需要控制初始化逻辑
if not hasattr(self, 'initialized'):
self.value = value
self.initialized = True
# 使用装饰器实现单例(更Pythonic)
def singleton(cls):
instances = {}
def get_instance(*args, **kwargs):
if cls not in instances:
instances[cls] = cls(*args, **kwargs)
return instances[cls]
return get_instance
@singleton
class Logger:
def __init__(self, level="INFO"):
self.level = level
print(f"日志级别设置为 {self.level}")
# 测试
if __name__ == "__main__":
print("=== 单例模式测试 ===")
s1 = Singleton("第一次")
s2 = Singleton("第二次")
print(f"s1 is s2: {s1 is s2}") # True
print(f"s1.value = {s1.value}, s2.value = {s2.value}") # 第二次, 注意初始化被覆盖
print("\n--- 装饰器单例 ---")
log1 = Logger("DEBUG")
log2 = Logger("ERROR")
print(f"log1 is log2: {log1 is log2}")
print(f"log1.level = {log1.level}, log2.level = {log2.level}")
输出:
bash
=== 单例模式测试 ===
创建第一个实例
返回已存在的实例
s1 is s2: True
s1.value = 第二次, s2.value = 第二次
--- 装饰器单例 ---
日志级别设置为 DEBUG
log1 is log2: True
log1.level = DEBUG, log2.level = DEBUG
优缺点:
-
优点:节省资源,全局唯一访问点。
-
缺点:在多线程环境需要加锁(Python可用
threading.Lock);可能隐藏依赖关系。
适用场景:配置类、连接池、线程池、注册表等。
2.2 工厂方法模式(Factory Method)
定义:定义一个创建对象的接口,但由子类决定实例化哪个类。将实例化延迟到子类。
问题场景:客户端不知道需要创建的具体对象类型,或者希望解耦对象创建与使用。
解决方案:创建抽象工厂类,具体工厂重写工厂方法。
代码示例:
bash
from abc import ABC, abstractmethod
# 产品抽象
class Animal(ABC):
@abstractmethod
def speak(self):
pass
class Dog(Animal):
def speak(self):
return "汪汪"
class Cat(Animal):
def speak(self):
return "喵喵"
# 工厂抽象
class AnimalFactory(ABC):
@abstractmethod
def create_animal(self) -> Animal:
pass
class DogFactory(AnimalFactory):
def create_animal(self) -> Animal:
return Dog()
class CatFactory(AnimalFactory):
def create_animal(self) -> Animal:
return Cat()
# 客户端
def animal_sound(factory: AnimalFactory):
animal = factory.create_animal()
print(animal.speak())
if __name__ == "__main__":
print("=== 工厂方法模式 ===")
animal_sound(DogFactory())
animal_sound(CatFactory())
输出:
进阶示例:参数化工厂方法
bash
class Shape(ABC):
@abstractmethod
def draw(self):
pass
class Circle(Shape):
def draw(self):
return "绘制圆形"
class Square(Shape):
def draw(self):
return "绘制方形"
class ShapeFactory:
def create_shape(self, shape_type):
if shape_type == "circle":
return Circle()
elif shape_type == "square":
return Square()
else:
raise ValueError("未知形状")
if __name__ == "__main__":
factory = ShapeFactory()
shapes = ["circle", "square", "circle"]
for s in shapes:
shape = factory.create_shape(s)
print(shape.draw())
输出:
优缺点:
-
优点:符合开闭原则,增加新产品只需增加对应工厂类。
-
缺点:每增加一种产品需要增加具体工厂类,系统复杂度增加。
适用场景:框架库中提供接口让用户扩展;创建逻辑复杂且经常变化。
2.3 抽象工厂模式(Abstract Factory)
定义:创建一系列相关或相互依赖对象的接口,无需指定具体类。
问题场景:系统需要生产多种产品族(如不同风格的UI组件:按钮、复选框),且产品之间搭配使用。
解决方案:定义抽象工厂,每个具体工厂生产一整套产品。
代码示例:
bash
from abc import ABC, abstractmethod
# 抽象产品 A
class Button(ABC):
@abstractmethod
def paint(self):
pass
# 抽象产品 B
class Checkbox(ABC):
@abstractmethod
def check(self):
pass
# 具体产品族1:Windows风格
class WinButton(Button):
def paint(self):
return "Win按钮绘制"
class WinCheckbox(Checkbox):
def check(self):
return "Win复选框勾选"
# 具体产品族2:Mac风格
class MacButton(Button):
def paint(self):
return "Mac按钮绘制"
class MacCheckbox(Checkbox):
def check(self):
return "Mac复选框勾选"
# 抽象工厂
class GUIFactory(ABC):
@abstractmethod
def create_button(self) -> Button:
pass
@abstractmethod
def create_checkbox(self) -> Checkbox:
pass
# 具体工厂
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()
# 客户端
def create_ui(factory: GUIFactory):
button = factory.create_button()
checkbox = factory.create_checkbox()
print(button.paint())
print(checkbox.check())
if __name__ == "__main__":
print("=== 抽象工厂模式(Windows)===")
create_ui(WinFactory())
print("\n=== 抽象工厂模式(Mac)===")
create_ui(MacFactory())
输出:
bash
=== 抽象工厂模式(Windows)===
Win按钮绘制
Win复选框勾选
=== 抽象工厂模式(Mac)===
Mac按钮绘制
Mac复选框勾选
优缺点:
-
优点:保证产品族内一致性;易于交换产品系列。
-
缺点:增加新产品族困难(需修改抽象工厂接口);扩展产品等级较麻烦。
适用场景:界面工具包、游戏风格切换、跨平台开发。
2.4 建造者模式(Builder)
定义:将复杂对象的构建与其表示分离,使同样的构建过程可以创建不同的表示。
问题场景:创建包含多个可选部分的对象(如电脑:CPU、内存、硬盘、显卡),构造函数参数过多且混乱。
解决方案:使用Director控制构建流程,Builder负责具体部件的装配。
代码示例:
bash
from abc import ABC, abstractmethod
# 产品
class Computer:
def __init__(self):
self.cpu = None
self.ram = None
self.storage = None
self.gpu = None
def __str__(self):
return f"Computer [CPU={self.cpu}, RAM={self.ram}, Storage={self.storage}, GPU={self.gpu}]"
# 抽象建造者
class ComputerBuilder(ABC):
@abstractmethod
def build_cpu(self):
pass
@abstractmethod
def build_ram(self):
pass
@abstractmethod
def build_storage(self):
pass
@abstractmethod
def build_gpu(self):
pass
@abstractmethod
def get_result(self) -> Computer:
pass
# 具体建造者:游戏电脑
class GamingComputerBuilder(ComputerBuilder):
def __init__(self):
self.computer = Computer()
def build_cpu(self):
self.computer.cpu = "Intel i9"
def build_ram(self):
self.computer.ram = "32GB DDR5"
def build_storage(self):
self.computer.storage = "1TB NVMe SSD"
def build_gpu(self):
self.computer.gpu = "NVIDIA RTX 4090"
def get_result(self) -> Computer:
return self.computer
# 具体建造者:办公电脑
class OfficeComputerBuilder(ComputerBuilder):
def __init__(self):
self.computer = Computer()
def build_cpu(self):
self.computer.cpu = "Intel i5"
def build_ram(self):
self.computer.ram = "16GB DDR4"
def build_storage(self):
self.computer.storage = "512GB SSD"
def build_gpu(self):
self.computer.gpu = "集成显卡"
def get_result(self) -> Computer:
return self.computer
# 指挥者
class Director:
def __init__(self, builder: ComputerBuilder):
self.builder = builder
def construct_computer(self):
self.builder.build_cpu()
self.builder.build_ram()
self.builder.build_storage()
self.builder.build_gpu()
return self.builder.get_result()
if __name__ == "__main__":
print("=== 建造者模式 ===")
gaming_builder = GamingComputerBuilder()
director = Director(gaming_builder)
gaming_pc = director.construct_computer()
print(f"游戏电脑配置: {gaming_pc}")
office_builder = OfficeComputerBuilder()
director.builder = office_builder
office_pc = director.construct_computer()
print(f"办公电脑配置: {office_pc}")
输出:
bash
=== 建造者模式 ===
游戏电脑配置: Computer [CPU=Intel i9, RAM=32GB DDR5, Storage=1TB NVMe SSD, GPU=NVIDIA RTX 4090]
办公电脑配置: Computer [CPU=Intel i5, RAM=16GB DDR4, Storage=512GB SSD, GPU=集成显卡]
优缺点:
-
优点:分步构建,精细控制;复用同一构建流程创建不同表示。
-
缺点:增加代码复杂度,需要多个类。
适用场景:复杂对象参数众多(尤其是可选参数)、配置对象、文档生成器(如PDF/HTML生成)。
3. 结构型模式
3.1 适配器模式(Adapter)
定义:将一个类的接口转换成客户希望的另一个接口,使原本因接口不兼容的类可以一起工作。
问题场景:现有类的方法签名与目标接口不符,无法直接使用。
解决方案:创建适配器类包装旧接口,转换调用。
代码示例:
bash
# 已有类(Adaptee)
class EuropeanSocket:
def voltage(self):
return 230
def plug_type(self):
return "圆形插头"
# 目标接口(Target)
class USASocket:
def voltage(self):
return 120
def plug_type(self):
return "扁平插头"
# 适配器:将欧式插座转为美式接口
class SocketAdapter(USASocket):
def __init__(self, european_socket: EuropeanSocket):
self.european_socket = european_socket
def voltage(self):
# 转换电压 230 -> 120(实际需要变压器,这里模拟)
return 120
def plug_type(self):
# 转换插头形状
return "扁平插头(适配)"
# 客户端只能使用USASocket
def charge_laptop(socket: USASocket):
print(f"充电电压: {socket.voltage()}V, 插头类型: {socket.plug_type()}")
if __name__ == "__main__":
print("=== 适配器模式 ===")
eu_socket = EuropeanSocket()
print(f"直接使用欧式插座: 电压{eu_socket.voltage()}V, {eu_socket.plug_type()}")
# 使用适配器
adapter = SocketAdapter(eu_socket)
charge_laptop(adapter)
输出:
bash
=== 适配器模式 ===
直接使用欧式插座: 电压230V, 圆形插头
充电电压: 120V, 插头类型: 扁平插头(适配)
进阶:类适配器(多重继承)
bash
class EuropeanVoltage:
def get_voltage(self):
return 230
class USASocketInterface:
def supply_power(self):
return 120
class Adapter(EuropeanVoltage, USASocketInterface):
def supply_power(self):
# 转换逻辑
return 120
if __name__ == "__main__":
adapter = Adapter()
print(f"适配器供电: {adapter.supply_power()}V")
优缺点:
-
优点:提高类的复用性;透明性(客户端只看到目标接口)。
-
缺点:过多适配器使系统复杂。
适用场景:集成第三方库、遗留系统改造、不同数据格式转换。
3.2 装饰器模式(Decorator)
定义:动态地给一个对象添加额外的职责,比继承更灵活。
问题场景:需要扩展一个类的功能,但又不想通过子类爆炸式增长。
解决方案:装饰器包装原有对象,在调用前后添加行为。
代码示例:
bash
from abc import ABC, abstractmethod
# 组件接口
class Coffee(ABC):
@abstractmethod
def cost(self) -> float:
pass
@abstractmethod
def description(self) -> str:
pass
# 具体组件
class SimpleCoffee(Coffee):
def cost(self) -> float:
return 5.0
def description(self) -> str:
return "基础咖啡"
# 装饰器基类
class CoffeeDecorator(Coffee):
def __init__(self, coffee: Coffee):
self._coffee = coffee
def cost(self) -> float:
return self._coffee.cost()
def description(self) -> str:
return self._coffee.description()
# 具体装饰器
class MilkDecorator(CoffeeDecorator):
def cost(self) -> float:
return self._coffee.cost() + 1.5
def description(self) -> str:
return self._coffee.description() + ", 加奶"
class SugarDecorator(CoffeeDecorator):
def cost(self) -> float:
return self._coffee.cost() + 0.8
def description(self) -> str:
return self._coffee.description() + ", 加糖"
class WhippedCreamDecorator(CoffeeDecorator):
def cost(self) -> float:
return self._coffee.cost() + 2.0
def description(self) -> str:
return self._coffee.description() + ", 奶油顶"
if __name__ == "__main__":
print("=== 装饰器模式 ===")
coffee = SimpleCoffee()
print(f"{coffee.description()} 价格: {coffee.cost()}元")
# 加奶
coffee_with_milk = MilkDecorator(coffee)
print(f"{coffee_with_milk.description()} 价格: {coffee_with_milk.cost()}元")
# 加奶加糖
coffee_with_milk_sugar = SugarDecorator(MilkDecorator(coffee))
print(f"{coffee_with_milk_sugar.description()} 价格: {coffee_with_milk_sugar.cost()}元")
# 豪华版:加奶+糖+奶油
deluxe = WhippedCreamDecorator(SugarDecorator(MilkDecorator(coffee)))
print(f"{deluxe.description()} 价格: {deluxe.cost()}元")
输出:
bash
=== 装饰器模式 ===
基础咖啡 价格: 5.0元
基础咖啡, 加奶 价格: 6.5元
基础咖啡, 加奶, 加糖 价格: 7.3元
基础咖啡, 加奶, 加糖, 奶油顶 价格: 9.3元
Python内置装饰器语法糖:函数装饰器也是该模式的体现。
bash
import functools
def log_call(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
print(f"调用 {func.__name__} 参数: {args} {kwargs}")
result = func(*args, **kwargs)
print(f"返回: {result}")
return result
return wrapper
@log_call
def add(a, b):
return a + b
print(add(3, 5))
优缺点:
-
优点:比继承更灵活,避免类爆炸;符合开闭原则。
-
缺点:多层装饰导致调试困难;可能产生很多小对象。
适用场景:动态添加功能(I/O流处理、GUI组件边框、日志记录等)。
3.3 代理模式(Proxy)
定义:为其他对象提供一种代理以控制对这个对象的访问。
问题场景:需要延迟加载、访问控制、日志记录或远程访问。
解决方案:代理类与真实类实现同一接口,代理持有真实对象的引用并控制访问。
代码示例:
bash
from abc import ABC, abstractmethod
# 抽象主题
class Image(ABC):
@abstractmethod
def display(self):
pass
# 真实主题:大图片加载耗时
class HighResolutionImage(Image):
def __init__(self, filename):
self.filename = filename
self.load_from_disk()
def load_from_disk(self):
print(f"正在从磁盘加载高清图片 {self.filename} (耗时3秒)...")
# 模拟耗时
import time
time.sleep(0.5) # 仅演示,实际可设为更长
print(f"加载完成")
def display(self):
print(f"显示图片: {self.filename}")
# 代理:延迟加载
class ImageProxy(Image):
def __init__(self, filename):
self.filename = filename
self.real_image = None
def display(self):
if self.real_image is None:
self.real_image = HighResolutionImage(self.filename)
self.real_image.display()
# 客户端
if __name__ == "__main__":
print("=== 代理模式(延迟加载)===")
img1 = ImageProxy("photo1.jpg")
img2 = ImageProxy("photo2.jpg")
print("第一次显示photo1:")
img1.display()
print("第二次显示photo1:")
img1.display()
print("显示photo2:")
img2.display()
输出:
bash
=== 代理模式(延迟加载)===
第一次显示photo1:
正在从磁盘加载高清图片 photo1.jpg (耗时3秒)...
加载完成
显示图片: photo1.jpg
第二次显示photo1:
显示图片: photo1.jpg
显示photo2:
正在从磁盘加载高清图片 photo2.jpg (耗时3秒)...
加载完成
显示图片: photo2.jpg
其他常见代理:
-
保护代理(控制访问权限)
-
远程代理(隐藏网络通信)
-
虚拟代理(延迟加载)
保护代理示例:
bash
class BankAccount:
def withdraw(self, amount):
print(f"取款 {amount} 元")
class AccountProxy:
def __init__(self, user_role):
self.role = user_role
self.account = BankAccount()
def withdraw(self, amount):
if self.role == "admin":
self.account.withdraw(amount)
else:
print("权限不足,无法取款")
if __name__ == "__main__":
proxy = AccountProxy("guest")
proxy.withdraw(100)
admin_proxy = AccountProxy("admin")
admin_proxy.withdraw(500)
输出:
优缺点:
-
优点:职责清晰,可控制访问,支持延迟加载。
-
缺点:增加系统复杂度,可能降低响应速度。
适用场景:远程代理(RPC)、虚拟代理(大对象加载)、安全代理(权限校验)。
3.4 外观模式(Facade)
定义:为子系统中的一组接口提供一个统一的简化接口。外观模式定义了一个高层接口,使子系统更易使用。
问题场景:复杂子系统依赖过多,客户端需要调用多个模块才能完成一个功能。
解决方案:创建外观类封装子系统的复杂交互。
代码示例:
bash
# 子系统类:音视频解码、投影仪、灯光、功放等
class DVDPlayer:
def on(self):
print("DVD播放器开机")
def play(self, movie):
print(f"播放电影 {movie}")
def off(self):
print("DVD播放器关机")
class Projector:
def on(self):
print("投影仪开机")
def wide_screen_mode(self):
print("设置为宽屏模式")
def off(self):
print("投影仪关机")
class SoundSystem:
def on(self):
print("音响系统开机")
def set_volume(self, level):
print(f"音量设置为 {level}")
def off(self):
print("音响系统关机")
class Lights:
def dim(self, level):
print(f"灯光调暗至 {level}%")
def on(self):
print("灯光全亮")
# 外观类:家庭影院
class HomeTheaterFacade:
def __init__(self, dvd, projector, sound, lights):
self.dvd = dvd
self.projector = projector
self.sound = sound
self.lights = lights
def watch_movie(self, movie):
print("\n准备观看电影...")
self.lights.dim(20)
self.projector.on()
self.projector.wide_screen_mode()
self.sound.on()
self.sound.set_volume(60)
self.dvd.on()
self.dvd.play(movie)
print("开始放映!\n")
def end_movie(self):
print("\n关闭电影...")
self.dvd.off()
self.sound.off()
self.projector.off()
self.lights.on()
print("电影结束,灯光亮起\n")
if __name__ == "__main__":
dvd = DVDPlayer()
projector = Projector()
sound = SoundSystem()
lights = Lights()
home_theater = HomeTheaterFacade(dvd, projector, sound, lights)
home_theater.watch_movie("阿凡达")
home_theater.end_movie()
输出:
bash
准备观看电影...
灯光调暗至 20%
投影仪开机
设置为宽屏模式
音响系统开机
音量设置为 60
DVD播放器开机
播放电影 阿凡达
开始放映!
关闭电影...
DVD播放器关机
音响系统关机
投影仪关机
灯光全亮
电影结束,灯光亮起
优缺点:
-
优点:简化客户端调用,降低耦合度;分层结构更清晰。
-
缺点:可能成为上帝对象,过度耦合所有子系统。
适用场景 :复杂库或框架的入口(如requests库简化HTTP调用);需要为复杂子系统提供简单接口。
4. 行为型模式
4.1 观察者模式(Observer)
定义:定义对象间一对多的依赖关系,当一个对象状态改变时,所有依赖它的对象都得到通知并自动更新。
问题场景:事件驱动系统、数据更新后需要刷新多个界面(如MVC中的模型与视图)。
解决方案:被观察者(Subject)维护观察者列表,状态变化时调用观察者更新方法。
代码示例:
bash
from abc import ABC, abstractmethod
# 观察者接口
class Observer(ABC):
@abstractmethod
def update(self, temperature, humidity, pressure):
pass
# 被观察者(主题)
class WeatherStation:
def __init__(self):
self.observers = []
self.temperature = 0
self.humidity = 0
self.pressure = 0
def attach(self, observer: Observer):
if observer not in self.observers:
self.observers.append(observer)
def detach(self, observer: Observer):
self.observers.remove(observer)
def notify(self):
for observer in self.observers:
observer.update(self.temperature, self.humidity, self.pressure)
def set_measurements(self, temp, hum, press):
self.temperature = temp
self.humidity = hum
self.pressure = press
self.notify()
# 具体观察者1:手机App显示
class PhoneDisplay(Observer):
def update(self, temperature, humidity, pressure):
print(f"手机App显示: 温度={temperature}°C, 湿度={humidity}%, 气压={pressure}hPa")
# 具体观察者2:大屏幕显示器
class LargeScreenDisplay(Observer):
def update(self, temperature, humidity, pressure):
print(f"大屏幕: 当前温度 {temperature}°C | 湿度 {humidity}%")
if __name__ == "__main__":
weather_station = WeatherStation()
phone = PhoneDisplay()
large_screen = LargeScreenDisplay()
weather_station.attach(phone)
weather_station.attach(large_screen)
print("=== 天气数据更新 ===")
weather_station.set_measurements(25, 65, 1013)
weather_station.set_measurements(27, 70, 1010)
print("\n解绑手机App后:")
weather_station.detach(phone)
weather_station.set_measurements(26, 68, 1012)
输出:
bash
=== 天气数据更新 ===
手机App显示: 温度=25°C, 湿度=65%, 气压=1013hPa
大屏幕: 当前温度 25°C | 湿度 65%
手机App显示: 温度=27°C, 湿度=70%, 气压=1010hPa
大屏幕: 当前温度 27°C | 湿度 70%
解绑手机App后:
大屏幕: 当前温度 26°C | 湿度 68%
Python内置事件机制 :可以使用weakref避免内存泄漏或使用asyncio等。
优缺点:
-
优点:支持广播通信,松耦合(主题只知道观察者接口)。
-
缺点:观察者太多或更新频繁影响性能;循环依赖可能导致死循环。
适用场景:事件处理系统、股票行情推送、GUI监听器、模型-视图-控制器(MVC)。
4.2 策略模式(Strategy)
定义:定义一系列算法,将每个算法封装起来,并使它们可以互相替换。策略模式让算法独立于使用它的客户端而变化。
问题场景:多种支付方式、排序算法切换、折扣计算等。
解决方案:定义策略接口,具体策略实现算法,上下文类组合策略。
代码示例:
bash
from abc import ABC, abstractmethod
# 策略接口
class PaymentStrategy(ABC):
@abstractmethod
def pay(self, amount):
pass
# 具体策略1:信用卡支付
class CreditCardPayment(PaymentStrategy):
def __init__(self, card_number, cvv):
self.card_number = card_number
self.cvv = cvv
def pay(self, amount):
print(f"使用信用卡 {self.card_number[-4:]} 支付 {amount} 元,CVV验证通过")
# 具体策略2:支付宝支付
class AlipayPayment(PaymentStrategy):
def __init__(self, account):
self.account = account
def pay(self, amount):
print(f"支付宝账户 {self.account} 支付 {amount} 元")
# 具体策略3:微信支付
class WechatPayment(PaymentStrategy):
def __init__(self, openid):
self.openid = openid
def pay(self, amount):
print(f"微信用户 {self.openid} 支付 {amount} 元")
# 上下文:购物车
class ShoppingCart:
def __init__(self):
self.items = []
self.payment_strategy = None
def add_item(self, item, price):
self.items.append((item, price))
def total(self):
return sum(price for _, price in self.items)
def set_payment_strategy(self, strategy: PaymentStrategy):
self.payment_strategy = strategy
def checkout(self):
total = self.total()
if self.payment_strategy is None:
raise Exception("请先设置支付策略")
self.payment_strategy.pay(total)
if __name__ == "__main__":
cart = ShoppingCart()
cart.add_item("Python编程书", 79)
cart.add_item("机械键盘", 299)
print(f"购物车总金额: {cart.total()}元")
# 使用信用卡支付
cart.set_payment_strategy(CreditCardPayment("1234-5678-9012-3456", "123"))
print("--- 信用卡支付 ---")
cart.checkout()
# 更换策略为支付宝
cart.set_payment_strategy(AlipayPayment("alice@example.com"))
print("--- 支付宝支付 ---")
cart.checkout()
输出:
bash
购物车总金额: 378元
--- 信用卡支付 ---
使用信用卡 3456 支付 378 元,CVV验证通过
--- 支付宝支付 ---
支付宝账户 alice@example.com 支付 378 元
结合lambda简化策略(Python特色):
bash
strategies = {
"add": lambda x, y: x + y,
"subtract": lambda x, y: x - y,
"multiply": lambda x, y: x * y,
}
def execute_strategy(op, a, b):
return strategies[op](a, b)
print(execute_strategy("add", 10, 5)) # 15
print(execute_strategy("multiply", 3, 4)) # 12
优缺点:
-
优点:消除条件语句,易于扩展新策略;策略可复用。
-
缺点:客户端必须了解不同策略;增加对象数量。
适用场景:多种算法变体(排序、压缩、加密);避免长if-else或switch。
4.3 模板方法模式(Template Method)
定义:定义一个操作中的算法骨架,将某些步骤延迟到子类中实现。子类可以重定义算法的特定步骤而不改变算法结构。
问题场景:多个子类共享相同步骤,但某些步骤实现各异(如数据挖掘:读取数据、分析、输出报告)。
解决方案:抽象类定义模板方法(通常为final),其中调用基本方法(抽象或hook)。
代码示例:
bash
from abc import ABC, abstractmethod
# 抽象类
class DataProcessor(ABC):
# 模板方法
def process(self):
self.load_data()
self.analyze_data()
self.save_results()
self.write_report() # hook方法可选覆写
def load_data(self):
print("从文件加载数据...")
@abstractmethod
def analyze_data(self):
pass
def save_results(self):
print("保存分析结果到数据库")
# hook方法(默认实现,子类可覆盖)
def write_report(self):
print("生成标准报告")
# 具体子类:销售数据分析
class SalesDataProcessor(DataProcessor):
def analyze_data(self):
print("分析销售额趋势,计算同比增长率")
def write_report(self):
print("生成销售报告PDF,附带图表")
# 具体子类:用户行为分析
class UserBehaviorProcessor(DataProcessor):
def analyze_data(self):
print("分析用户点击流,计算转化率")
# 使用默认的write_report,不覆盖
if __name__ == "__main__":
print("=== 销售数据处理 ===")
sales = SalesDataProcessor()
sales.process()
print("\n=== 用户行为数据处理 ===")
behavior = UserBehaviorProcessor()
behavior.process()
输出:
bash
=== 销售数据处理 ===
从文件加载数据...
分析销售额趋势,计算同比增长率
保存分析结果到数据库
生成销售报告PDF,附带图表
=== 用户行为数据处理 ===
从文件加载数据...
分析用户点击流,计算转化率
保存分析结果到数据库
生成标准报告
进阶:钩子方法控制流程
bash
class CoffeeMaker(ABC):
def prepare_recipe(self):
self.boil_water()
self.brew()
self.pour_in_cup()
if self.customer_wants_condiments():
self.add_condiments()
def boil_water(self):
print("烧开水")
def pour_in_cup(self):
print("倒入杯中")
@abstractmethod
def brew(self):
pass
@abstractmethod
def add_condiments(self):
pass
def customer_wants_condiments(self):
return True # 钩子
class Tea(CoffeeMaker):
def brew(self):
print("浸泡茶叶")
def add_condiments(self):
print("加柠檬")
def customer_wants_condiments(self):
# 询问用户
answer = input("要加柠檬吗?(y/n): ")
return answer.lower() == 'y'
Tea().prepare_recipe()
优缺点:
-
优点:复用代码,避免重复;符合好莱坞原则(不要调用我们,我们调用你)。
-
缺点:每个不同实现需要子类,增加了复杂度;子类对模板方法的影响有限。
适用场景:框架基类、算法骨架固定且部分可变、工作流引擎。
4.4 状态模式(State)
定义:允许对象在其内部状态改变时改变它的行为,看起来好像修改了其类。
问题场景:对象的行为依赖于其状态,并且状态转换逻辑复杂(如电梯、订单状态机)。
解决方案:将状态封装为独立类,上下文委托给当前状态对象执行行为。
代码示例:
bash
from abc import ABC, abstractmethod
# 状态接口
class State(ABC):
@abstractmethod
def handle(self, context):
pass
# 具体状态:已订货
class OrderedState(State):
def handle(self, context):
print("订单已创建,等待支付")
context.state = PaidState() # 状态转移
# 具体状态:已支付
class PaidState(State):
def handle(self, context):
print("支付完成,正在备货")
context.state = ShippedState()
# 具体状态:已发货
class ShippedState(State):
def handle(self, context):
print("已发货,等待确认收货")
context.state = DeliveredState()
# 具体状态:已完成
class DeliveredState(State):
def handle(self, context):
print("订单已完成,感谢购买!")
# 上下文:订单
class Order:
def __init__(self):
self.state = OrderedState()
def next_state(self):
self.state.handle(self)
def cancel(self):
# 可定义取消逻辑,某些状态允许取消
print("订单已取消")
if __name__ == "__main__":
order = Order()
order.next_state() # 已订货 -> 等待支付
order.next_state() # 已支付 -> 备货
order.next_state() # 已发货 -> 等待收货
order.next_state() # 已完成
order.next_state() # 已完成状态无转移,将再次执行(但DeliveredState内部没有转移,只会打印)
输出:
bash
订单已创建,等待支付
支付完成,正在备货
已发货,等待确认收货
订单已完成,感谢购买!
订单已完成,感谢购买!
优化:在状态类中增加条件防止无限循环(实际开发中可以增加状态转换条件检查)。
电梯状态示例:
bash
class ElevatorState(ABC):
@abstractmethod
def open_door(self, elevator): pass
@abstractmethod
def close_door(self, elevator): pass
@abstractmethod
def move(self, elevator): pass
class IdleState(ElevatorState):
def open_door(self, elevator):
print("开门")
elevator.state = DoorOpenState()
def close_door(self, elevator):
print("门已关,无法重复关闭")
def move(self, elevator):
print("空闲状态,未移动")
class DoorOpenState(ElevatorState):
def open_door(self, elevator):
print("门已开")
def close_door(self, elevator):
print("关门")
elevator.state = IdleState()
def move(self, elevator):
print("门未关,不能移动")
class Elevator:
def __init__(self):
self.state = IdleState()
def open(self): self.state.open_door(self)
def close(self): self.state.close_door(self)
def move(self): self.state.move(self)
e = Elevator()
e.open()
e.move()
e.close()
e.move()
优缺点:
-
优点:将状态转换逻辑局部化;增加新状态容易;减少条件分支。
-
缺点:状态过多会增加类的数量;状态模式对开闭原则支持较好(增加状态不变现有代码)。
适用场景:有限状态机、游戏角色不同形态、订单/工作流状态管理。
4.5 责任链模式(Chain of Responsibility)
定义:使多个对象都有机会处理请求,避免请求发送者与接收者耦合。将这些对象连成一条链,沿着链传递请求直到被处理。
问题场景:审批流程(员工请假->主管->经理->HR)、日志级别处理、过滤器链。
解决方案:每个处理器持有下一个引用,处理不了就转发。
代码示例:
bash
from abc import ABC, abstractmethod
# 处理器抽象
class Handler(ABC):
def __init__(self):
self._next_handler = None
def set_next(self, handler):
self._next_handler = handler
return handler
@abstractmethod
def handle(self, request):
if self._next_handler:
return self._next_handler.handle(request)
return None
# 具体处理器1:技术负责人(可处理500元以下报销)
class TechLead(Handler):
def handle(self, request):
if request["type"] == "reimbursement" and request["amount"] <= 500:
print(f"技术负责人审批了 {request['amount']} 元报销单")
return True
else:
print("技术负责人无法处理,转交上级")
return super().handle(request)
# 具体处理器2:项目经理(可处理1000元以下)
class ProjectManager(Handler):
def handle(self, request):
if request["type"] == "reimbursement" and request["amount"] <= 1000:
print(f"项目经理审批了 {request['amount']} 元报销单")
return True
else:
print("项目经理无法处理,转交上级")
return super().handle(request)
# 具体处理器3:总监(可处理5000元以下)
class Director(Handler):
def handle(self, request):
if request["type"] == "reimbursement" and request["amount"] <= 5000:
print(f"总监审批了 {request['amount']} 元报销单")
return True
else:
print("总监无法处理,需要CEO批准")
return super().handle(request)
if __name__ == "__main__":
# 构建责任链
tech_lead = TechLead()
pm = ProjectManager()
director = Director()
tech_lead.set_next(pm).set_next(director)
requests = [
{"type": "reimbursement", "amount": 200},
{"type": "reimbursement", "amount": 800},
{"type": "reimbursement", "amount": 3000},
{"type": "reimbursement", "amount": 10000},
]
for req in requests:
print(f"\n处理报销 {req['amount']} 元")
result = tech_lead.handle(req)
if not result:
print(f"{req['amount']} 元报销未被任何领导审批")
输出:
bash
处理报销 200 元
技术负责人审批了 200 元报销单
处理报销 800 元
技术负责人无法处理,转交上级
项目经理审批了 800 元报销单
处理报销 3000 元
技术负责人无法处理,转交上级
项目经理无法处理,转交上级
总监审批了 3000 元报销单
处理报销 10000 元
技术负责人无法处理,转交上级
项目经理无法处理,转交上级
总监无法处理,需要CEO批准
10000 元报销未被任何领导审批
优缺点:
-
优点:降低耦合,增加灵活性;动态调整链。
-
缺点:请求可能未被处理;调试困难(链路过长)。
适用场景:日志框架(不同级别去不同输出)、Servlet过滤器、事件冒泡。
5. 总结与下载说明
本文详细介绍了15种常见的设计模式,每种模式均提供了完整的Python代码示例 和实际运行输出,确保你可以复制代码并亲自运行验证。理解这些模式不仅能提升代码质量,还能让你在团队协作中使用统一的术语交流。