设计模式是软件工程中经过验证的、可复用的解决方案,用于解决特定上下文中反复出现的设计问题。掌握设计模式能帮助你编写更优雅、可维护、可扩展的代码。本文将以Python为例,从基础概念到高级应用,详细讲解15种常用设计模式。每种模式均包含定义、问题场景、解决方案、代码示例(带输出)、优缺点及适用场景。所有代码均可复制到本地运行,助你彻底理解设计模式的精髓。
目录
- 责任链模式(Chain of Responsibility)
1. 设计模式简介
设计模式主要分为三大类:
- 创建型模式
- 结构型模式:组合类或对象以形成更大结构,如适配器、装饰器等。
- 行为型模式
Python作为动态语言,部分模式实现更简洁(例如装饰器内置支持),但理解其背后的思想依然至关重要。
2. 创建型模式
2.1 单例模式(Singleton)
定义:确保一个类只有一个实例,并提供全局访问点。
问题场景:配置文件管理、数据库连接池、日志记录器等对象只需一个全局实例时。
解决方案:通过重写__new__方法或使用元类控制实例创建。
代码示例:
classSingleton:"""经典单例实现""" _instance = Nonedef__new__(cls, *args, **kwargs):if cls._instance isNone: print("创建第一个实例") cls._instance = super().__new__(cls)else: print("返回已存在的实例")return cls._instancedef__init__(self, value=None):# 注意:__init__每次都会执行,需要控制初始化逻辑ifnot hasattr(self, 'initialized'): self.value = value self.initialized = True# 使用装饰器实现单例(更Pythonic)defsingleton(cls): instances = {}defget_instance(*args, **kwargs):if cls notin instances: instances[cls] = cls(*args, **kwargs)return instances[cls]return get_instance@singletonclassLogger: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}")
输出:
===单例模式测试===创建第一个实例返回已存在的实例s1 is s2:Trues1.value=第二次,s2.value=第二次---装饰器单例---日志级别设置为DEBUGlog1 is log2:Truelog1.level=DEBUG,log2.level=DEBUG
优缺点:
- 缺点:在多线程环境需要加锁(Python可用threading.Lock);可能隐藏依赖关系。
适用场景:配置类、连接池、线程池、注册表等。
2.2 工厂方法模式(Factory Method)
定义:定义一个创建对象的接口,但由子类决定实例化哪个类。将实例化延迟到子类。
问题场景:客户端不知道需要创建的具体对象类型,或者希望解耦对象创建与使用。
解决方案:创建抽象工厂类,具体工厂重写工厂方法。
代码示例:
from abc import ABC, abstractmethod# 产品抽象classAnimal(ABC): @abstractmethoddefspeak(self):passclassDog(Animal):defspeak(self):return"汪汪"classCat(Animal):defspeak(self):return"喵喵"# 工厂抽象classAnimalFactory(ABC): @abstractmethoddefcreate_animal(self) -> Animal:passclassDogFactory(AnimalFactory):defcreate_animal(self) -> Animal:return Dog()classCatFactory(AnimalFactory):defcreate_animal(self) -> Animal:return Cat()# 客户端defanimal_sound(factory: AnimalFactory): animal = factory.create_animal() print(animal.speak())if __name__ == "__main__": print("=== 工厂方法模式 ===") animal_sound(DogFactory()) animal_sound(CatFactory())
输出:
进阶示例:参数化工厂方法
classShape(ABC): @abstractmethoddefdraw(self):passclassCircle(Shape):defdraw(self):return"绘制圆形"classSquare(Shape):defdraw(self):return"绘制方形"classShapeFactory:defcreate_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组件:按钮、复选框),且产品之间搭配使用。
解决方案:定义抽象工厂,每个具体工厂生产一整套产品。
代码示例:
from abc import ABC, abstractmethod# 抽象产品 AclassButton(ABC): @abstractmethoddefpaint(self):pass# 抽象产品 BclassCheckbox(ABC): @abstractmethoddefcheck(self):pass# 具体产品族1:Windows风格classWinButton(Button):defpaint(self):return"Win按钮绘制"classWinCheckbox(Checkbox):defcheck(self):return"Win复选框勾选"# 具体产品族2:Mac风格classMacButton(Button):defpaint(self):return"Mac按钮绘制"classMacCheckbox(Checkbox):defcheck(self):return"Mac复选框勾选"# 抽象工厂classGUIFactory(ABC): @abstractmethoddefcreate_button(self) -> Button:pass @abstractmethoddefcreate_checkbox(self) -> Checkbox:pass# 具体工厂classWinFactory(GUIFactory):defcreate_button(self) -> Button:return WinButton()defcreate_checkbox(self) -> Checkbox:return WinCheckbox()classMacFactory(GUIFactory):defcreate_button(self) -> Button:return MacButton()defcreate_checkbox(self) -> Checkbox:return MacCheckbox()# 客户端defcreate_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())
输出:
=== 抽象工厂模式(Windows)===Win按钮绘制Win复选框勾选=== 抽象工厂模式(Mac)===Mac按钮绘制Mac复选框勾选
优缺点:
- 缺点:增加新产品族困难(需修改抽象工厂接口);扩展产品等级较麻烦。
适用场景:界面工具包、游戏风格切换、跨平台开发。
2.4 建造者模式(Builder)
定义:将复杂对象的构建与其表示分离,使同样的构建过程可以创建不同的表示。
问题场景:创建包含多个可选部分的对象(如电脑:CPU、内存、硬盘、显卡),构造函数参数过多且混乱。
解决方案:使用Director控制构建流程,Builder负责具体部件的装配。
代码示例:
from abc import ABC, abstractmethod# 产品classComputer:def__init__(self):self.cpu = Noneself.ram = Noneself.storage = Noneself.gpu = Nonedef__str__(self):return f"Computer [CPU={self.cpu}, RAM={self.ram}, Storage={self.storage}, GPU={self.gpu}]"# 抽象建造者classComputerBuilder(ABC): @abstractmethoddefbuild_cpu(self): pass @abstractmethoddefbuild_ram(self): pass @abstractmethoddefbuild_storage(self): pass @abstractmethoddefbuild_gpu(self): pass @abstractmethoddefget_result(self) -> Computer: pass# 具体建造者:游戏电脑classGamingComputerBuilder(ComputerBuilder):def__init__(self):self.computer = Computer()defbuild_cpu(self):self.computer.cpu = "Intel i9"defbuild_ram(self):self.computer.ram = "32GB DDR5"defbuild_storage(self):self.computer.storage = "1TB NVMe SSD"defbuild_gpu(self):self.computer.gpu = "NVIDIA RTX 4090"defget_result(self) -> Computer:returnself.computer# 具体建造者:办公电脑classOfficeComputerBuilder(ComputerBuilder):def__init__(self):self.computer = Computer()defbuild_cpu(self):self.computer.cpu = "Intel i5"defbuild_ram(self):self.computer.ram = "16GB DDR4"defbuild_storage(self):self.computer.storage = "512GB SSD"defbuild_gpu(self):self.computer.gpu = "集成显卡"defget_result(self) -> Computer:returnself.computer# 指挥者classDirector:def__init__(self, builder: ComputerBuilder):self.builder = builderdefconstruct_computer(self):self.builder.build_cpu()self.builder.build_ram()self.builder.build_storage()self.builder.build_gpu()returnself.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}")
输出:
=== 建造者模式 ===游戏电脑配置: 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)
定义:将一个类的接口转换成客户希望的另一个接口,使原本因接口不兼容的类可以一起工作。
问题场景:现有类的方法签名与目标接口不符,无法直接使用。
解决方案:创建适配器类包装旧接口,转换调用。
代码示例:
# 已有类(Adaptee)classEuropeanSocket:defvoltage(self):return230defplug_type(self):return"圆形插头"# 目标接口(Target)classUSASocket:defvoltage(self):return120defplug_type(self):return"扁平插头"# 适配器:将欧式插座转为美式接口classSocketAdapter(USASocket):def__init__(self, european_socket: EuropeanSocket): self.european_socket = european_socketdefvoltage(self):# 转换电压 230 -> 120(实际需要变压器,这里模拟)return120defplug_type(self):# 转换插头形状return"扁平插头(适配)"# 客户端只能使用USASocketdefcharge_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)
输出:
=== 适配器模式 ===直接使用欧式插座: 电压230V, 圆形插头充电电压: 120V, 插头类型: 扁平插头(适配)
进阶:类适配器(多重继承)
classEuropeanVoltage:defget_voltage(self):return230classUSASocketInterface:defsupply_power(self):return120classAdapter(EuropeanVoltage, USASocketInterface):defsupply_power(self):# 转换逻辑return120if __name__ == "__main__": adapter = Adapter() print(f"适配器供电: {adapter.supply_power()}V")
优缺点:
- 优点:提高类的复用性;透明性(客户端只看到目标接口)。
适用场景:集成第三方库、遗留系统改造、不同数据格式转换。
3.2 装饰器模式(Decorator)
定义:动态地给一个对象添加额外的职责,比继承更灵活。
问题场景:需要扩展一个类的功能,但又不想通过子类爆炸式增长。
解决方案:装饰器包装原有对象,在调用前后添加行为。
代码示例:
from abc import ABC, abstractmethod# 组件接口classCoffee(ABC): @abstractmethoddefcost(self) -> float:pass @abstractmethoddefdescription(self) -> str:pass# 具体组件classSimpleCoffee(Coffee):defcost(self) -> float:return5.0defdescription(self) -> str:return"基础咖啡"# 装饰器基类classCoffeeDecorator(Coffee):def__init__(self, coffee: Coffee): self._coffee = coffeedefcost(self) -> float:return self._coffee.cost()defdescription(self) -> str:return self._coffee.description()# 具体装饰器classMilkDecorator(CoffeeDecorator):defcost(self) -> float:return self._coffee.cost() + 1.5defdescription(self) -> str:return self._coffee.description() + ", 加奶"classSugarDecorator(CoffeeDecorator):defcost(self) -> float:return self._coffee.cost() + 0.8defdescription(self) -> str:return self._coffee.description() + ", 加糖"classWhippedCreamDecorator(CoffeeDecorator):defcost(self) -> float:return self._coffee.cost() + 2.0defdescription(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()}元")
输出:
===装饰器模式===基础咖啡价格:5.0元基础咖啡,加奶价格:6.5元基础咖啡,加奶,加糖价格:7.3元基础咖啡,加奶,加糖,奶油顶价格:9.3元
Python内置装饰器语法糖:函数装饰器也是该模式的体现。
import functoolsdeflog_call(func): @functools.wraps(func)defwrapper(*args, **kwargs): print(f"调用 {func.__name__} 参数: {args}{kwargs}") result = func(*args, **kwargs) print(f"返回: {result}")return resultreturn wrapper@log_calldefadd(a, b):return a + bprint(add(3, 5))
优缺点:
适用场景:动态添加功能(I/O流处理、GUI组件边框、日志记录等)。
3.3 代理模式(Proxy)
定义:为其他对象提供一种代理以控制对这个对象的访问。
问题场景:需要延迟加载、访问控制、日志记录或远程访问。
解决方案:代理类与真实类实现同一接口,代理持有真实对象的引用并控制访问。
代码示例:
from abc import ABC, abstractmethod# 抽象主题classImage(ABC): @abstractmethoddefdisplay(self):pass# 真实主题:大图片加载耗时classHighResolutionImage(Image):def__init__(self, filename): self.filename = filename self.load_from_disk()defload_from_disk(self): print(f"正在从磁盘加载高清图片 {self.filename} (耗时3秒)...")# 模拟耗时import time time.sleep(0.5) # 仅演示,实际可设为更长 print(f"加载完成")defdisplay(self): print(f"显示图片: {self.filename}")# 代理:延迟加载classImageProxy(Image):def__init__(self, filename): self.filename = filename self.real_image = Nonedefdisplay(self):if self.real_image isNone: 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()
输出:
=== 代理模式(延迟加载)===第一次显示photo1:正在从磁盘加载高清图片 photo1.jpg (耗时3秒)...加载完成显示图片: photo1.jpg第二次显示photo1:显示图片: photo1.jpg显示photo2:正在从磁盘加载高清图片 photo2.jpg (耗时3秒)...加载完成显示图片: photo2.jpg
其他常见代理:
保护代理示例:
classBankAccount:defwithdraw(self, amount): print(f"取款 {amount} 元")classAccountProxy:def__init__(self, user_role):self.role = user_roleself.account = BankAccount()defwithdraw(self, amount):ifself.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)
定义:为子系统中的一组接口提供一个统一的简化接口。外观模式定义了一个高层接口,使子系统更易使用。
问题场景:复杂子系统依赖过多,客户端需要调用多个模块才能完成一个功能。
解决方案:创建外观类封装子系统的复杂交互。
代码示例:
# 子系统类:音视频解码、投影仪、灯光、功放等classDVDPlayer:defon(self): print("DVD播放器开机")defplay(self, movie): print(f"播放电影 {movie}")defoff(self): print("DVD播放器关机")classProjector:defon(self): print("投影仪开机")defwide_screen_mode(self): print("设置为宽屏模式")defoff(self): print("投影仪关机")classSoundSystem:defon(self): print("音响系统开机")defset_volume(self, level): print(f"音量设置为 {level}")defoff(self): print("音响系统关机")classLights:defdim(self, level): print(f"灯光调暗至 {level}%")defon(self): print("灯光全亮")# 外观类:家庭影院classHomeTheaterFacade:def__init__(self, dvd, projector, sound, lights):self.dvd = dvdself.projector = projectorself.sound = soundself.lights = lightsdefwatch_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")defend_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()
输出:
准备观看电影...灯光调暗至20%投影仪开机设置为宽屏模式音响系统开机音量设置为60DVD播放器开机播放电影阿凡达开始放映!关闭电影...DVD播放器关机音响系统关机投影仪关机灯光全亮电影结束,灯光亮起
优缺点:
- 优点:简化客户端调用,降低耦合度;分层结构更清晰。
适用场景:复杂库或框架的入口(如requests库简化HTTP调用);需要为复杂子系统提供简单接口。
4. 行为型模式
4.1 观察者模式(Observer)
定义:定义对象间一对多的依赖关系,当一个对象状态改变时,所有依赖它的对象都得到通知并自动更新。
问题场景:事件驱动系统、数据更新后需要刷新多个界面(如MVC中的模型与视图)。
解决方案:被观察者(Subject)维护观察者列表,状态变化时调用观察者更新方法。
代码示例:
from abc import ABC, abstractmethod# 观察者接口classObserver(ABC): @abstractmethoddefupdate(self, temperature, humidity, pressure): pass# 被观察者(主题)classWeatherStation:def__init__(self):self.observers = []self.temperature = 0self.humidity = 0self.pressure = 0defattach(self, observer: Observer):if observer notinself.observers:self.observers.append(observer)defdetach(self, observer: Observer):self.observers.remove(observer)defnotify(self):for observer inself.observers: observer.update(self.temperature, self.humidity, self.pressure)defset_measurements(self, temp, hum, press):self.temperature = tempself.humidity = humself.pressure = pressself.notify()# 具体观察者1:手机App显示classPhoneDisplay(Observer):defupdate(self, temperature, humidity, pressure): print(f"手机App显示: 温度={temperature}°C, 湿度={humidity}%, 气压={pressure}hPa")# 具体观察者2:大屏幕显示器classLargeScreenDisplay(Observer):defupdate(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)
输出:
=== 天气数据更新 ===手机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)
定义:定义一系列算法,将每个算法封装起来,并使它们可以互相替换。策略模式让算法独立于使用它的客户端而变化。
问题场景:多种支付方式、排序算法切换、折扣计算等。
解决方案:定义策略接口,具体策略实现算法,上下文类组合策略。
代码示例:
from abc import ABC, abstractmethod# 策略接口classPaymentStrategy(ABC): @abstractmethoddefpay(self, amount):pass# 具体策略1:信用卡支付classCreditCardPayment(PaymentStrategy):def__init__(self, card_number, cvv): self.card_number = card_number self.cvv = cvvdefpay(self, amount): print(f"使用信用卡 {self.card_number[-4:]} 支付 {amount} 元,CVV验证通过")# 具体策略2:支付宝支付classAlipayPayment(PaymentStrategy):def__init__(self, account): self.account = accountdefpay(self, amount): print(f"支付宝账户 {self.account} 支付 {amount} 元")# 具体策略3:微信支付classWechatPayment(PaymentStrategy):def__init__(self, openid): self.openid = openiddefpay(self, amount): print(f"微信用户 {self.openid} 支付 {amount} 元")# 上下文:购物车classShoppingCart:def__init__(self): self.items = [] self.payment_strategy = Nonedefadd_item(self, item, price): self.items.append((item, price))deftotal(self):return sum(price for _, price in self.items)defset_payment_strategy(self, strategy: PaymentStrategy): self.payment_strategy = strategydefcheckout(self): total = self.total()if self.payment_strategy isNone: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()
输出:
购物车总金额:378元---信用卡支付---使用信用卡3456支付378元,CVV验证通过---支付宝支付---支付宝账户alice@example.com支付378元
结合lambda简化策略(Python特色):
strategies = {"add": lambda x, y: x + y,"subtract": lambda x, y: x - y,"multiply": lambda x, y: x * y,}defexecute_strategy(op, a, b):return strategies[op](a, b)print(execute_strategy("add", 10, 5)) # 15print(execute_strategy("multiply", 3, 4)) # 12
优缺点:
适用场景:多种算法变体(排序、压缩、加密);避免长if-else或switch。
4.3 模板方法模式(Template Method)
定义:定义一个操作中的算法骨架,将某些步骤延迟到子类中实现。子类可以重定义算法的特定步骤而不改变算法结构。
问题场景:多个子类共享相同步骤,但某些步骤实现各异(如数据挖掘:读取数据、分析、输出报告)。
解决方案:抽象类定义模板方法(通常为final),其中调用基本方法(抽象或hook)。
代码示例:
from abc import ABC, abstractmethod# 抽象类classDataProcessor(ABC):# 模板方法defprocess(self): self.load_data() self.analyze_data() self.save_results() self.write_report() # hook方法可选覆写defload_data(self): print("从文件加载数据...") @abstractmethoddefanalyze_data(self):passdefsave_results(self): print("保存分析结果到数据库")# hook方法(默认实现,子类可覆盖)defwrite_report(self): print("生成标准报告")# 具体子类:销售数据分析classSalesDataProcessor(DataProcessor):defanalyze_data(self): print("分析销售额趋势,计算同比增长率")defwrite_report(self): print("生成销售报告PDF,附带图表")# 具体子类:用户行为分析classUserBehaviorProcessor(DataProcessor):defanalyze_data(self): print("分析用户点击流,计算转化率")# 使用默认的write_report,不覆盖if __name__ == "__main__": print("=== 销售数据处理 ===") sales = SalesDataProcessor() sales.process() print("\n=== 用户行为数据处理 ===") behavior = UserBehaviorProcessor() behavior.process()
输出:
=== 销售数据处理 ===从文件加载数据...分析销售额趋势,计算同比增长率保存分析结果到数据库生成销售报告PDF,附带图表=== 用户行为数据处理 ===从文件加载数据...分析用户点击流,计算转化率保存分析结果到数据库生成标准报告
进阶:钩子方法控制流程
classCoffeeMaker(ABC):defprepare_recipe(self):self.boil_water()self.brew()self.pour_in_cup()ifself.customer_wants_condiments():self.add_condiments()defboil_water(self): print("烧开水")defpour_in_cup(self): print("倒入杯中") @abstractmethoddefbrew(self): pass @abstractmethoddefadd_condiments(self): passdefcustomer_wants_condiments(self):return True # 钩子classTea(CoffeeMaker):defbrew(self): print("浸泡茶叶")defadd_condiments(self): print("加柠檬")defcustomer_wants_condiments(self):# 询问用户 answer = input("要加柠檬吗?(y/n): ")return answer.lower() == 'y'Tea().prepare_recipe()
优缺点:
- 优点:复用代码,避免重复;符合好莱坞原则(不要调用我们,我们调用你)。
- 缺点:每个不同实现需要子类,增加了复杂度;子类对模板方法的影响有限。
适用场景:框架基类、算法骨架固定且部分可变、工作流引擎。
4.4 状态模式(State)
定义:允许对象在其内部状态改变时改变它的行为,看起来好像修改了其类。
问题场景:对象的行为依赖于其状态,并且状态转换逻辑复杂(如电梯、订单状态机)。
解决方案:将状态封装为独立类,上下文委托给当前状态对象执行行为。
代码示例:
from abc import ABC, abstractmethod# 状态接口classState(ABC): @abstractmethoddefhandle(self, context):pass# 具体状态:已订货classOrderedState(State):defhandle(self, context): print("订单已创建,等待支付") context.state = PaidState() # 状态转移# 具体状态:已支付classPaidState(State):defhandle(self, context): print("支付完成,正在备货") context.state = ShippedState()# 具体状态:已发货classShippedState(State):defhandle(self, context): print("已发货,等待确认收货") context.state = DeliveredState()# 具体状态:已完成classDeliveredState(State):defhandle(self, context): print("订单已完成,感谢购买!")# 上下文:订单classOrder:def__init__(self): self.state = OrderedState()defnext_state(self): self.state.handle(self)defcancel(self):# 可定义取消逻辑,某些状态允许取消 print("订单已取消")if __name__ == "__main__": order = Order() order.next_state() # 已订货 -> 等待支付 order.next_state() # 已支付 -> 备货 order.next_state() # 已发货 -> 等待收货 order.next_state() # 已完成 order.next_state() # 已完成状态无转移,将再次执行(但DeliveredState内部没有转移,只会打印)
输出:
订单已创建,等待支付支付完成,正在备货已发货,等待确认收货订单已完成,感谢购买!订单已完成,感谢购买!
优化:在状态类中增加条件防止无限循环(实际开发中可以增加状态转换条件检查)。
电梯状态示例:
classElevatorState(ABC): @abstractmethoddefopen_door(self, elevator): pass @abstractmethoddefclose_door(self, elevator): pass @abstractmethoddefmove(self, elevator): passclassIdleState(ElevatorState):defopen_door(self, elevator): print("开门") elevator.state = DoorOpenState()defclose_door(self, elevator): print("门已关,无法重复关闭")defmove(self, elevator): print("空闲状态,未移动")classDoorOpenState(ElevatorState):defopen_door(self, elevator): print("门已开")defclose_door(self, elevator): print("关门") elevator.state = IdleState()defmove(self, elevator): print("门未关,不能移动")classElevator:def__init__(self):self.state = IdleState()defopen(self): self.state.open_door(self)defclose(self): self.state.close_door(self)defmove(self): self.state.move(self)e = Elevator()e.open()e.move()e.close()e.move()
优缺点:
- 优点:将状态转换逻辑局部化;增加新状态容易;减少条件分支。
- 缺点:状态过多会增加类的数量;状态模式对开闭原则支持较好(增加状态不变现有代码)。
适用场景:有限状态机、游戏角色不同形态、订单/工作流状态管理。
4.5 责任链模式(Chain of Responsibility)
定义:使多个对象都有机会处理请求,避免请求发送者与接收者耦合。将这些对象连成一条链,沿着链传递请求直到被处理。
问题场景:审批流程(员工请假->主管->经理->HR)、日志级别处理、过滤器链。
解决方案:每个处理器持有下一个引用,处理不了就转发。
代码示例:
from abc import ABC, abstractmethod# 处理器抽象classHandler(ABC):def__init__(self): self._next_handler = Nonedefset_next(self, handler): self._next_handler = handlerreturn handler @abstractmethoddefhandle(self, request):if self._next_handler:return self._next_handler.handle(request)returnNone# 具体处理器1:技术负责人(可处理500元以下报销)classTechLead(Handler):defhandle(self, request):if request["type"] == "reimbursement"and request["amount"] <= 500: print(f"技术负责人审批了 {request['amount']} 元报销单")returnTrueelse: print("技术负责人无法处理,转交上级")return super().handle(request)# 具体处理器2:项目经理(可处理1000元以下)classProjectManager(Handler):defhandle(self, request):if request["type"] == "reimbursement"and request["amount"] <= 1000: print(f"项目经理审批了 {request['amount']} 元报销单")returnTrueelse: print("项目经理无法处理,转交上级")return super().handle(request)# 具体处理器3:总监(可处理5000元以下)classDirector(Handler):defhandle(self, request):if request["type"] == "reimbursement"and request["amount"] <= 5000: print(f"总监审批了 {request['amount']} 元报销单")returnTrueelse: 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)ifnot result: print(f"{req['amount']} 元报销未被任何领导审批")
输出:
处理报销200元技术负责人审批了200元报销单处理报销800元技术负责人无法处理,转交上级项目经理审批了800元报销单处理报销3000元技术负责人无法处理,转交上级项目经理无法处理,转交上级总监审批了3000元报销单处理报销10000元技术负责人无法处理,转交上级项目经理无法处理,转交上级总监无法处理,需要CEO批准10000元报销未被任何领导审批
优缺点:
适用场景:日志框架(不同级别去不同输出)、Servlet过滤器、事件冒泡。
5. 总结与下载说明
本文详细介绍了15种常见的设计模式,每种模式均提供了完整的Python代码示例和实际运行输出,确保你可以复制代码并亲自运行验证。理解这些模式不仅能提升代码质量,还能让你在团队协作中使用统一的术语交流。
额外建议:
- 学习模式时,先理解问题场景,不要为了用模式而用模式。
- 结合Python内置特性(如装饰器、上下文管理器)与模式思想,写出更Pythonic的代码。
希望这篇长文能成为你Python设计模式之路的得力助手。如果有任何疑问或建议,欢迎在评论区交流!
Happy Coding!