23 种经典设计模式 + J2EE 扩展模式:Python 代码实战全指南

AgenticCoding·十二月创作之星挑战赛 10w+人浏览 541人参与

序言:为什么需要设计模式?

假设你是一位刚接触编程的开发者,接到一个需求:开发一个 “咖啡店订单系统”,支持用户点单咖啡(如浓缩咖啡、美式咖啡),并可以添加配料(如牛奶、糖、香草)。你可能会直接写这样的代码:

class Coffee:
    def __init__(self, type: str, has_milk: bool = False, has_sugar: bool = False):
        self.type = type
        self.has_milk = has_milk
        self.has_sugar = has_sugar
    
    def cost(self):
        base = 20 if self.type == "Espresso" else 15
        milk = 5 if self.has_milk else 0
        sugar = 2 if self.has_sugar else 0
        return base + milk
    
    def description(self):
        desc = self.type
        if self.has_milk:
            desc += " with Milk"
        if self.has_sugar:
            desc += " with Sugar"
        return desc

这样的代码能满足当前需求,但问题很快就会出现:

  • 若新增 10 种咖啡和 5 种配料,构造函数会变得无比复杂;
  • 若配料价格变化,需修改cost方法的硬编码;
  • 若要添加 “双倍牛奶”“少糖” 等特殊需求,需大面积修改现有代码。

设计模式就是为解决这类 “重复出现的软件设计问题” 而总结的可复用解决方案模板。它不是现成的代码,而是一种 “设计思路”—— 让代码更易读、易维护、易扩展。

1994 年,四位软件工程师(Erich Gamma、Richard Helm、Ralph Johnson、John Vlissides,合称 GoF)出版了《设计模式:可复用面向对象软件的基础》,首次提出 23 种经典设计模式,并将其分为三大类:创建型模式(控制对象创建的方式)、结构型模式(类或对象的组合方式)、行为型模式(对象间的通信与职责分配)。此外,针对 Java 企业级开发场景,还衍生出J2EE 设计模式,用于解决分布式、分层架构下的通用问题。

本文将以零基础可理解的方式,详细讲解这 4 类设计模式,每个模式均包含:现实类比、核心问题、实现步骤、Python 代码示例、应用场景、优缺点。


一、设计模式的分类与核心思想

1. 创建型模式(Creational Patterns):5 种

核心思想:控制对象的创建过程,避免硬编码依赖具体类,提高代码的灵活性。

  • 包含:单例模式、工厂方法模式、抽象工厂模式、建造者模式、原型模式。

2. 结构型模式(Structural Patterns):7 种

核心思想:将类或对象组合成更大的结构,同时保持结构的灵活性和可复用性。

  • 包含:适配器模式、桥接模式、组合模式、装饰器模式、外观模式、享元模式、代理模式。

3. 行为型模式(Behavioral Patterns):11 种

核心思想:定义对象间的通信规则与职责分配,解决 “对象如何交互” 的问题。

  • 包含:责任链模式、命令模式、迭代器模式、中介者模式、备忘录模式、观察者模式、状态模式、策略模式、模板方法模式、访问者模式、解释器模式。

4. J2EE 设计模式:企业级扩展

核心思想:针对 Java EE(企业级 Java 平台)的分层架构、分布式通信、资源管理等场景,提炼的通用解决方案。

  • 包含:MVC 模式、数据访问对象(DAO)模式、前端控制器模式、服务定位器模式、业务代表模式等。

二、创建型模式详解

创建型模式的本质是 “封装对象创建的细节”,让客户端代码不直接依赖具体类的构造函数,而是通过 “工厂”“建造者” 等中间层创建对象。

2.1 单例模式(Singleton Pattern)

现实类比:公司的 CEO

一个公司只能有一位 CEO,所有员工咨询 CEO 时,都会找到同一个人。

核心问题:保证一个类仅有一个实例,并提供一个全局访问点

常用于资源密集型对象(如数据库连接池、线程池、配置管理器),避免重复创建浪费资源。

实现方式:5 种经典实现(Python 版)
(1)饿汉式:类加载时直接创建实例
# 饿汉式单例模式
class SingletonEager:
    # 类加载阶段(Python导入时)自动创建唯一实例
    __instance = object.__new__(cls)
    
    # 禁止外部通过__init__重复初始化
    def __init__(self):
        if SingletonEager.__instance is not None:
            raise RuntimeError("该类已实例化,请勿重复创建")
    
    # 提供全局访问点
    @classmethod
    def get_instance(cls):
        return cls.__instance

# 测试代码
if __name__ == "__main__":
    ceo1 = SingletonEager.get_instance()
    ceo2 = SingletonEager.get_instance()
    print(f"是否为同一实例:{ceo1 is ceo2}")  # 输出:True

优缺点

  • 优点:线程安全(Python 导入时执行,无并发问题)、实现简单;
  • 缺点:提前加载,若实例未被使用则浪费资源。
(2)懒汉式:使用时才创建实例
# 懒汉式单例模式(线程不安全)
class SingletonLazy:
    __instance = None
    
    def __init__(self):
        if SingletonLazy.__instance is not None:
            raise RuntimeError("该类已实例化")
    
    @classmethod
    def get_instance(cls):
        if cls.__instance is None:
            cls.__instance = cls()  # 第一次调用时创建实例
        return cls.__instance

优缺点

  • 优点:延迟加载,节省资源;
  • 缺点:多线程环境下可能创建多个实例(两个线程同时检查到__instance 为 None,都会执行创建)。
(3)线程安全的懒汉式:加锁保护
import threading

# 线程安全的懒汉式单例模式
class SingletonLazySafe:
    __instance = None
    __lock = threading.Lock()  # 定义锁对象
    
    def __init__(self):
        if SingletonLazySafe.__instance is not None:
            raise RuntimeError("该类已实例化")
    
    @classmethod
    def get_instance(cls):
        with cls.__lock:  # 加锁,确保同一时间只有一个线程执行创建逻辑
            if cls.__instance is None:
                cls.__instance = cls()
            return cls.__instance

优缺点

  • 优点:线程安全、延迟加载;
  • 缺点:每次获取实例都要加锁,效率低。
(4)双重检查锁定(DCL):优化效率
import threading

# 双重检查锁定单例模式
class SingletonDCL:
    __instance = None
    __lock = threading.Lock()
    
    def __init__(self):
        if SingletonDCL.__instance is not None:
            raise RuntimeError("该类已实例化")
    
    @classmethod
    def get_instance(cls):
        # 第一次检查:无锁,快速判断是否已创建实例
        if cls.__instance is None:
            with cls.__lock:
                # 第二次检查:加锁后再次判断(防止多个线程进入第一次检查的间隙后重复创建)
                if cls.__instance is None:
                    cls.__instance = cls()
        return cls.__instance

优缺点

  • 优点:线程安全、延迟加载、效率高(仅第一次创建时加锁);
  • 缺点:实现稍复杂。
(5)元类实现:Pythonic 的单例

Python 中,“类是元类的实例”。通过定义元类,可以控制类的创建过程,确保仅生成一个实例。

# 元类单例模式
class SingletonMeta(type):
    __instances = {}  # 保存所有单例类的实例
    
    # 控制类的实例化过程
    def __call__(cls, *args, **kwargs):
        if cls not in cls.__instances:
            # 创建实例并保存
            cls.__instances[cls] = super().__call__(*args, **kwargs)
        return cls.__instances[cls]

# 使用元类创建单例类
class ConfigManager(metaclass=SingletonMeta):
    def __init__(self):
        self.config = {"host": "localhost", "port": 3306}

# 测试代码
if __name__ == "__main__":
    config1 = ConfigManager()
    config2 = ConfigManager()
    print(f"是否为同一实例:{config1 is config2}")  # 输出:True

优缺点

  • 优点:代码简洁、支持继承、最符合 Python 特性;
  • 缺点:需要理解元类的工作机制,对零基础开发者有一定门槛。
应用场景
  • 数据库连接池、Redis 客户端实例;
  • 系统配置管理器、日志记录器;
  • 线程池、线程安全的计数器。

2.2 工厂方法模式(Factory Method Pattern)

现实类比:手机工厂

苹果手机由苹果工厂生产,华为手机由华为工厂生产 —— 所有工厂都遵循 “生产手机” 的统一标准,但具体实现不同。

核心问题:定义一个创建对象的接口,但让子类决定实例化哪个类,将对象创建的细节延迟到子类。

解决 “客户端直接依赖具体类” 的问题,符合开闭原则(对扩展开放,对修改关闭)。

实现步骤
  1. 定义抽象产品类:规范产品的共同方法(如Phone类的call());
  2. 定义具体产品类:继承抽象产品类,实现具体逻辑(如IPhoneHuaweiPhone);
  3. 定义抽象工厂类:规范工厂的创建方法(如PhoneFactorycreate_phone());
  4. 定义具体工厂类:继承抽象工厂类,实现产品的创建逻辑(如IPhoneFactoryHuaweiPhoneFactory)。
Python 代码示例
# 1. 抽象产品类:手机
class Phone:
    def call(self):
        pass

# 2. 具体产品类:苹果手机
class IPhone(Phone):
    def call(self):
        print("IPhone正在打电话")

# 2. 具体产品类:华为手机
class HuaweiPhone(Phone):
    def call(self):
        print("HuaweiPhone正在打电话")

# 3. 抽象工厂类:手机工厂
class PhoneFactory:
    def create_phone(self):
        pass

# 4. 具体工厂类:苹果手机工厂
class IPhoneFactory(PhoneFactory):
    def create_phone(self):
        return IPhone()  # 创建并返回苹果手机实例

# 4. 具体工厂类:华为手机工厂
class HuaweiPhoneFactory(PhoneFactory):
    def create_phone(self):
        return HuaweiPhone()  # 创建并返回华为手机实例

# 客户端代码
if __name__ == "__main__":
    # 客户端仅依赖抽象工厂和抽象产品,不直接接触具体类
    iphone_factory = IPhoneFactory()
    iphone = iphone_factory.create_phone()
    iphone.call()  # 输出:IPhone正在打电话
    
    huawei_factory = HuaweiPhoneFactory()
    huawei = huawei_factory.create_phone()
    huawei.call()  # 输出:HuaweiPhone正在打电话
    
    # 若新增小米手机,仅需:
    # 1. 定义XiaomiPhone类继承Phone;
    # 2. 定义XiaomiPhoneFactory类继承PhoneFactory;
    # 客户端无需修改任何现有代码,符合开闭原则。
应用场景
  • 当客户端需要创建多个具有共同接口的产品时;
  • 当需要将产品创建的细节与客户端分离时;
  • 当产品类型可能随时间扩展时。
与 “简单工厂模式” 的区别

简单工厂模式是 “工厂方法模式的简化版”:仅定义一个静态工厂类,通过条件判断创建不同产品。但简单工厂模式违反开闭原则(新增产品需修改工厂的条件判断逻辑),因此不属于 GoF 的 23 种经典设计模式。


2.3 抽象工厂模式(Abstract Factory Pattern)

现实类比:电子设备工厂

苹果工厂不仅生产手机,还生产电脑、平板 —— 所有产品都属于 “苹果生态”;华为工厂同理,生产 “华为生态” 的设备。抽象工厂模式用于创建一系列相关或相互依赖的产品族

核心问题:提供一个创建一系列相关或相互依赖产品的接口,无需指定其具体类。

解决 “工厂方法模式仅能创建单个产品” 的问题,适用于需要 “配套产品” 的场景。

实现步骤
  1. 定义抽象产品族:如PhoneComputer
  2. 定义具体产品族:如ApplePhoneAppleComputer(苹果产品族),HuaweiPhoneHuaweiComputer(华为产品族);
  3. 定义抽象工厂类:规范创建产品族的方法(如DeviceFactorycreate_phone()create_computer());
  4. 定义具体工厂类:继承抽象工厂类,实现产品族的创建逻辑(如AppleFactoryHuaweiFactory)。
Python 代码示例
# 1. 抽象产品族1:手机
class Phone:
    def call(self):
        pass

# 2. 具体产品族1-1:苹果手机
class ApplePhone(Phone):
    def call(self):
        print("Apple Phone正在打电话")

# 2. 具体产品族1-2:华为手机
class HuaweiPhone(Phone):
    def call(self):
        print("Huawei Phone正在打电话")

# 1. 抽象产品族2:电脑
class Computer:
    def run(self):
        pass

# 2. 具体产品族2-1:苹果电脑
class AppleComputer(Computer):
    def run(self):
        print("Apple Computer正在运行")

# 2. 具体产品族2-2:华为电脑
class HuaweiComputer(Computer):
    def run(self):
        print("Huawei Computer正在运行")

# 3. 抽象工厂类:电子设备工厂
class DeviceFactory:
    def create_phone(self):
        pass
    
    def create_computer(self):
        pass

# 4. 具体工厂类1:苹果设备工厂
class AppleFactory(DeviceFactory):
    def create_phone(self):
        return ApplePhone()
    
    def create_computer(self):
        return AppleComputer()

# 4. 具体工厂类2:华为设备工厂
class HuaweiFactory(DeviceFactory):
    def create_phone(self):
        return HuaweiPhone()
    
    def create_computer(self):
        return HuaweiComputer()

# 客户端代码
if __name__ == "__main__":
    # 创建苹果设备工厂
    apple_factory = AppleFactory()
    apple_phone = apple_factory.create_phone()
    apple_computer = apple_factory.create_computer()
    apple_phone.call()  # 输出:Apple Phone正在打电话
    apple_computer.run()  # 输出:Apple Computer正在运行
    
    # 创建华为设备工厂
    huawei_factory = HuaweiFactory()
    huawei_phone = huawei_factory.create_phone()
    huawei_computer = huawei_factory.create_computer()
    huawei_phone.call()  # 输出:Huawei Phone正在打电话
    huawei_computer.run()  # 输出:Huawei Computer正在运行
    
    # 若新增小米设备族,仅需:
    # 1. 定义XiaomiPhone、XiaomiComputer;
    # 2. 定义XiaomiFactory;
    # 客户端无需修改现有代码。
应用场景
  • 当需要创建 “产品族”(如同一品牌的手机、电脑、平板)时;
  • 当系统需要独立于产品的创建、组合和表示方式时;
  • 当系统配置为使用多个产品族中的一个时。

2.4 建造者模式(Builder Pattern)

现实类比:汽车组装

汽车由引擎、底盘、车身、轮胎等部件组成,不同型号的汽车(如 SUV、轿车)部件组合方式不同。建造者模式将 “产品的构建过程” 与 “最终产品” 分离,让同一构建过程可以创建不同的产品。

核心问题:将复杂对象的构建过程分解为多个步骤,允许逐步构建并灵活组合,最终生成不同配置的产品。

解决 “复杂对象构造函数参数过多” 的问题,如Car(engine, chassis, body, tire, color, seat, ...)

实现步骤
  1. 定义产品类:包含所有部件的复杂对象(如Car);
  2. 定义建造者接口:规范产品的构建步骤(如CarBuilderbuild_engine()build_chassis()等);
  3. 定义具体建造者:实现建造者接口,构建具体的产品部件(如SUVBuilderSedanBuilder);
  4. 定义指挥者:管理建造者的构建流程,确保按顺序执行步骤(如CarDirectorconstruct_car())。
Python 代码示例
# 1. 产品类:汽车
class Car:
    def __init__(self):
        self.engine = None  # 引擎
        self.chassis = None  # 底盘
        self.body = None  # 车身
        self.tire = None  # 轮胎
        self.color = "白色"  # 默认颜色
    
    def __str__(self):
        return f"汽车配置:引擎={self.engine},底盘={self.chassis},车身={self.body},轮胎={self.tire},颜色={self.color}"

# 2. 建造者接口:汽车建造者
class CarBuilder:
    def build_engine(self):
        pass
    
    def build_chassis(self):
        pass
    
    def build_body(self):
        pass
    
    def build_tire(self):
        pass
    
    def get_car(self):
        pass

# 3. 具体建造者1:SUV建造者
class SUVBuilder(CarBuilder):
    def __init__(self):
        self.car = Car()  # 创建空汽车对象
    
    def build_engine(self):
        self.car.engine = "3.0T V6引擎"
    
    def build_chassis(self):
        self.car.chassis = "SUV专用底盘"
    
    def build_body(self):
        self.car.body = "SUV硬派车身"
    
    def build_tire(self):
        self.car.tire = "越野轮胎"
    
    def get_car(self):
        return self.car  # 返回构建完成的SUV

# 3. 具体建造者2:轿车建造者
class SedanBuilder(CarBuilder):
    def __init__(self):
        self.car = Car()
    
    def build_engine(self):
        self.car.engine = "1.5T L4引擎"
    
    def build_chassis(self):
        self.car.chassis = "轿车舒适底盘"
    
    def build_body(self):
        self.car.body = "轿车流线车身"
    
    def build_tire(self):
        self.car.tire = "静音轮胎"
    
    def get_car(self):
        return self.car  # 返回构建完成的轿车

# 4. 指挥者:汽车组装导演
class CarDirector:
    def __init__(self, builder):
        self.builder = builder
    
    # 控制构建流程:按顺序执行建造步骤
    def construct_car(self):
        self.builder.build_engine()
        self.builder.build_chassis()
        self.builder.build_body()
        self.builder.build_tire()

# 客户端代码
if __name__ == "__main__":
    # 构建SUV
    suv_builder = SUVBuilder()
    suv_director = CarDirector(suv_builder)
    suv_director.construct_car()  # 执行组装流程
    suv = suv_builder.get_car()
    print(suv)  # 输出:汽车配置:引擎=3.0T V6引擎,底盘=SUV专用底盘,车身=SUV硬派车身,轮胎=越野轮胎,颜色=白色
    
    # 构建轿车
    sedan_builder = SedanBuilder()
    sedan_director = CarDirector(sedan_builder)
    sedan_director.construct_car()
    sedan = sedan_builder.get_car()
    print(sedan)  # 输出:汽车配置:引擎=1.5T L4引擎,底盘=轿车舒适底盘,车身=轿车流线车身,轮胎=静音轮胎,颜色=白色
    
    # 自定义颜色(扩展构建步骤)
    sedan.color = "黑色"
    print(sedan)  # 输出:颜色=黑色
应用场景
  • 当产品是复杂对象(包含多个部件、构建步骤)时;
  • 当需要灵活配置产品(如不同型号、不同颜色、不同功能)时;
  • 当需要将产品的构建与表示分离时。

2.5 原型模式(Prototype Pattern)

现实类比:复印机

当需要复制一份复杂文档时,直接使用复印机复制(克隆)比重新编写效率更高。原型模式通过 “克隆已有对象” 的方式创建新对象,避免重复执行复杂的初始化过程。

核心问题:通过克隆已有实例创建新对象,而不是通过构造函数重新初始化。

解决 “创建复杂对象的成本过高” 的问题,如需要从数据库查询大量数据才能初始化的对象。

实现方式:浅克隆与深克隆
  • 浅克隆:仅克隆对象本身及基本数据类型成员,引用类型成员仍指向原对象(Python 中copy.copy());
  • 深克隆:克隆对象本身及所有成员(包括引用类型成员),生成完全独立的副本(Python 中copy.deepcopy())。
Python 代码示例
import copy

# 原型类:文档
class Document:
    def __init__(self, title: str, content: str, images: list):
        self.title = title
        self.content = content
        self.images = images  # 引用类型成员(列表)
    
    # 浅克隆方法
    def shallow_copy(self):
        return copy.copy(self)
    
    # 深克隆方法
    def deep_copy(self):
        return copy.deepcopy(self)

# 客户端代码
if __name__ == "__main__":
    # 原始文档
    original_doc = Document("设计模式", "这是一篇关于设计模式的文档", ["图1.png", "图2.png"])
    print(f"原始文档:标题={original_doc.title},内容={original_doc.content},图片={original_doc.images}")
    print(f"原始文档图片列表地址:{id(original_doc.images)}")
    
    # 浅克隆
    shallow_clone = original_doc.shallow_copy()
    shallow_clone.title = "设计模式(浅克隆版)"
    shallow_clone.images.append("图3.png")  # 修改引用类型成员
    print(f"\n浅克隆文档:标题={shallow_clone.title},内容={shallow_clone.content},图片={shallow_clone.images}")
    print(f"浅克隆文档图片列表地址:{id(shallow_clone.images)}")  # 与原始文档相同
    print(f"原始文档图片列表:{original_doc.images}")  # 原始文档的图片列表也被修改了!
    
    # 深克隆
    deep_clone = original_doc.deep_copy()
    deep_clone.title = "设计模式(深克隆版)"
    deep_clone.images.append("图4.png")  # 修改引用类型成员
    print(f"\n深克隆文档:标题={deep_clone.title},内容={deep_clone.content},图片={deep_clone.images}")
    print(f"深克隆文档图片列表地址:{id(deep_clone.images)}")  # 与原始文档不同
    print(f"原始文档图片列表:{original_doc.images}")  # 原始文档的图片列表未被修改
应用场景
  • 当创建对象的成本远高于克隆成本时(如需要网络请求、数据库查询、复杂计算);
  • 当需要批量创建相似对象时;
  • 当需要避免构造函数的副作用时。

三、结构型模式详解

结构型模式的本质是 “组合类或对象以形成更大的结构”,同时保持结构的灵活性和可复用性。它关注的是类与对象之间的 “关系”(如继承、聚合、组合)。

3.1 适配器模式(Adapter Pattern)

现实类比:电源适配器

中国的电源插座是 220V 交流电,而手机充电器需要 5V 直流电 —— 电源适配器将 220V 转换为 5V,让不兼容的接口可以协同工作。

核心问题:将一个类的接口转换为客户端期望的另一个接口,解决 “接口不兼容” 的问题。

适配器模式分为类适配器(通过继承实现)和对象适配器(通过组合实现),后者更灵活,是 GoF 推荐的方式。

实现步骤
  1. 定义目标接口:客户端期望的接口(如Target);
  2. 定义适配者类:需要被适配的现有接口(如Adaptee);
  3. 定义适配器类:实现目标接口,并组合或继承适配者类,将适配者的方法转换为目标接口的方法。
Python 代码示例:对象适配器
# 1. 目标接口:客户端期望的电源接口(输出5V)
class TargetPower:
    def output_5v(self):
        pass

# 2. 适配者类:现有的电源接口(输出220V)
class AdapteePower:
    def output_220v(self):
        print("输出220V交流电")

# 3. 适配器类:电源适配器(将220V转换为5V)
class PowerAdapter(TargetPower):
    def __init__(self, adaptee):
        self.adaptee = adaptee  # 组合适配者对象
    
    def output_5v(self):
        self.adaptee.output_220v()  # 调用适配者的方法
        print("通过适配器转换为5V直流电")  # 适配逻辑

# 客户端代码
if __name__ == "__main__":
    # 客户端仅依赖目标接口TargetPower
    power_220v = AdapteePower()
    adapter = PowerAdapter(power_220v)
    adapter.output_5v()  # 输出:
                         # 输出220V交流电
                         # 通过适配器转换为5V直流电
应用场景
  • 当需要使用现有类,但它的接口与客户端期望的不一致时;
  • 当需要复用多个现有类,但它们的接口不统一时;
  • 当需要与第三方库集成,但第三方库的接口与系统接口不兼容时。

3.2 桥接模式(Bridge Pattern)

现实类比:笔与颜色

笔有 “钢笔”“铅笔” 等类型,颜色有 “红色”“蓝色” 等 —— 若为每种笔 - 颜色组合创建一个类(如RedPenBluePenRedPencilBluePencil),会导致类爆炸(若有 N 种笔和 M 种颜色,则需 N×M 个类)。桥接模式将 “笔类型” 与 “颜色” 分离为两个独立的维度,通过 “桥接”(组合)的方式灵活组合。

核心问题:将抽象部分与实现部分分离,使它们可以独立变化,避免类爆炸。

桥接模式的关键是组合替代继承:将一个维度的实现作为另一个维度的成员变量。

实现步骤
  1. 定义实现维度接口:如颜色接口Color
  2. 定义具体实现类:如RedColorBlueColor
  3. 定义抽象维度类:如笔类Pen,组合实现维度的接口;
  4. 定义具体抽象类:如Pen的子类FountainPenPencil
Python 代码示例
# 1. 实现维度接口:颜色
class Color:
    def apply_color(self):
        pass

# 2. 具体实现类1:红色
class RedColor(Color):
    def apply_color(self):
        return "红色"

# 2. 具体实现类2:蓝色
class BlueColor(Color):
    def apply_color(self):
        return "蓝色"

# 3. 抽象维度类:笔
class Pen:
    def __init__(self, color: Color):
        self.color = color  # 桥接:组合颜色接口
    
    def draw(self):
        pass

# 4. 具体抽象类1:钢笔
class FountainPen(Pen):
    def draw(self):
        print(f"用{self.color.apply_color()}的钢笔绘画")

# 4. 具体抽象类2:铅笔
class Pencil(Pen):
    def draw(self):
        print(f"用{self.color.apply_color()}的铅笔绘画")

# 客户端代码
if __name__ == "__main__":
    # 红色钢笔
    red_pen = FountainPen(RedColor())
    red_pen.draw()  # 输出:用红色的钢笔绘画
    
    # 蓝色铅笔
    blue_pencil = Pencil(BlueColor())
    blue_pencil.draw()  # 输出:用蓝色的铅笔绘画
    
    # 新增绿色(实现维度扩展)
    # class GreenColor(Color): ...
    # green_pen = FountainPen(GreenColor())
    # 无需修改Pen或FountainPen类
    
    # 新增毛笔(抽象维度扩展)
    # class BrushPen(Pen): ...
    # red_brush = BrushPen(RedColor())
    # 无需修改Color或RedColor类
应用场景
  • 当一个类存在两个或多个独立变化的维度(如笔的类型与颜色、操作系统与 UI 组件)时;
  • 当需要避免类爆炸(如 N×M 个类)时;
  • 当需要扩展多个维度(如新增笔类型或颜色)时。

3.3 组合模式(Composite Pattern)

现实类比:文件系统

文件系统由 “文件” 和 “文件夹” 组成 —— 文件夹可以包含文件或子文件夹,无论操作文件还是文件夹,都可以使用统一的接口(如open()delete())。

核心问题:将对象组合成树形结构,并让客户端可以统一处理单个对象和组合对象

组合模式的关键是抽象组件类:规范叶子节点(单个对象)和容器节点(组合对象)的共同接口。

实现步骤
  1. 定义抽象组件类:如FileSystemItem,规范open()delete()等方法;
  2. 定义叶子节点类:如File,实现抽象组件的方法;
  3. 定义容器节点类:如Folder,实现抽象组件的方法,并维护一个子组件列表。
Python 代码示例
# 1. 抽象组件类:文件系统项
class FileSystemItem:
    def open(self):
        pass
    
    def delete(self):
        pass

# 2. 叶子节点类:文件
class File(FileSystemItem):
    def __init__(self, name: str):
        self.name = name
    
    def open(self):
        print(f"打开文件:{self.name}")
    
    def delete(self):
        print(f"删除文件:{self.name}")

# 3. 容器节点类:文件夹
class Folder(FileSystemItem):
    def __init__(self, name: str):
        self.name = name
        self.children = []  # 维护子组件列表
    
    # 新增子组件
    def add(self, item: FileSystemItem):
        self.children.append(item)
    
    # 删除子组件
    def remove(self, item: FileSystemItem):
        self.children.remove(item)
    
    def open(self):
        print(f"打开文件夹:{self.name}")
        # 递归打开所有子组件
        for child in self.children:
            child.open()
    
    def delete(self):
        print(f"删除文件夹:{self.name}")
        # 递归删除所有子组件
        for child in self.children:
            child.delete()

# 客户端代码
if __name__ == "__main__":
    # 创建文件
    file1 = File("笔记.txt")
    file2 = File("照片.jpg")
    file3 = File("文档.pdf")
    
    # 创建文件夹
    folder1 = Folder("个人资料")
    folder2 = Folder("工作资料")
    
    # 组合结构
    folder1.add(file1)
    folder1.add(file2)
    folder2.add(file3)
    
    # 创建根文件夹
    root = Folder("根目录")
    root.add(folder1)
    root.add(folder2)
    
    # 统一处理组合对象和单个对象
    print("=== 打开根目录 ===")
    root.open()  # 输出:
                 # 打开文件夹:根目录
                 # 打开文件夹:个人资料
                 # 打开文件:笔记.txt
                 # 打开文件:照片.jpg
                 # 打开文件夹:工作资料
                 # 打开文件:文档.pdf
    
    print("\n=== 删除个人资料文件夹 ===")
    folder1.delete()  # 输出:
                      # 删除文件夹:个人资料
                      # 删除文件:笔记.txt
                      # 删除文件:照片.jpg
应用场景
  • 当需要处理树形结构的数据(如文件系统、菜单、组织结构)时;
  • 当需要统一接口处理单个对象和组合对象时;
  • 当需要递归遍历组合结构时。

3.4 装饰器模式(Decorator Pattern)

现实类比:咖啡配料

浓缩咖啡(Espresso)可以加牛奶、糖、香草等配料 —— 每种配料都会增加咖啡的价格和描述,但不需要修改咖啡本身的类。装饰器模式通过动态包裹对象的方式,在不修改原有类的情况下添加功能。

核心问题:不修改原有类的情况下,动态地为对象添加功能,支持多层嵌套装饰。

装饰器模式与 Python 的语法糖@decorator思想一致,但 GoF 的装饰器模式是一种 “对象组合” 的设计思路。

实现步骤
  1. 定义抽象组件类:如Coffee,规范cost()(价格)和description()(描述)方法;
  2. 定义具体组件类:如EspressoAmericano,实现抽象组件的方法;
  3. 定义抽象装饰器类:继承抽象组件类,组合抽象组件对象;
  4. 定义具体装饰器类:如MilkSugarVanilla,实现抽象装饰器的方法,添加新功能。
Python 代码示例
# 1. 抽象组件类:咖啡
class Coffee:
    def cost(self) -> float:
        pass
    
    def description(self) -> str:
        pass

# 2. 具体组件类1:浓缩咖啡
class Espresso(Coffee):
    def cost(self) -> float:
        return 20.0  # 基础价格20元
    
    def description(self) -> str:
        return "Espresso"  # 基础描述

# 2. 具体组件类2:美式咖啡
class Americano(Coffee):
    def cost(self) -> float:
        return 15.0
    
    def description(self) -> str:
        return "Americano"

# 3. 抽象装饰器类:咖啡配料
class CondimentDecorator(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()

# 4. 具体装饰器类1:牛奶(价格+5元)
class Milk(CondimentDecorator):
    def cost(self) -> float:
        return self._coffee.cost() + 5.0
    
    def description(self) -> str:
        return f"{self._coffee.description()}, Milk"

# 4. 具体装饰器类2:糖(价格+2元)
class Sugar(CondimentDecorator):
    def cost(self) -> float:
        return self._coffee.cost() + 2.0
    
    def description(self) -> str:
        return f"{self._coffee.description()}, Sugar"

# 4. 具体装饰器类3:香草(价格+3元)
class Vanilla(CondimentDecorator):
    def cost(self) -> float:
        return self._coffee.cost() + 3.0
    
    def description(self) -> str:
        return f"{self._coffee.description()}, Vanilla"

# 客户端代码
if __name__ == "__main__":
    # 纯浓缩咖啡
    espresso = Espresso()
    print(f"{espresso.description()}: {espresso.cost()}元")  # 输出:Espresso: 20.0元
    
    # 浓缩咖啡+牛奶
    espresso_with_milk = Milk(espresso)
    print(f"{espresso_with_milk.description()}: {espresso_with_milk.cost()}元")  # 输出:Espresso, Milk: 25.0元
    
    # 浓缩咖啡+牛奶+糖+香草
    espresso_with_all = Vanilla(Sugar(Milk(espresso)))
    print(f"{espresso_with_all.description()}: {espresso_with_all.cost()}元")  # 输出:Espresso, Milk, Sugar, Vanilla: 30.0元
    
    # 新增配料“焦糖”仅需定义Caramel类,无需修改原有代码
    # class Caramel(CondimentDecorator): ...
    # espresso_with_caramel = Caramel(espresso)
    # print(f"{espresso_with_caramel.description()}: {espresso_with_caramel.cost()}元")
应用场景
  • 当需要动态为对象添加功能,且功能可以组合时;
  • 修改原有类会违反开闭原则时;
  • 当需要多层嵌套功能(如咖啡加多种配料)时。

3.5 外观模式(Facade Pattern)

现实类比:电脑开机

电脑开机需要依次启动 CPU、内存、硬盘、显卡、显示器等部件 —— 若让用户手动操作每一步,会非常复杂。外观模式提供一个 “统一的入口”(如开机按钮),隐藏内部的复杂流程。

核心问题:为复杂的子系统提供一个简化的统一接口,降低客户端与子系统的耦合度。

外观模式的关键是封装子系统的复杂性,只暴露客户端需要的接口。

实现步骤
  1. 定义子系统类:如CPUMemoryHardDisk等,实现各自的功能;
  2. 定义外观类:组合所有子系统对象,提供简化的统一接口(如ComputerFacadestartup()shutdown())。
Python 代码示例
# 1. 子系统类1:CPU
class CPU:
    def start(self):
        print("CPU开始运行")
    
    def shutdown(self):
        print("CPU停止运行")

# 1. 子系统类2:内存
class Memory:
    def load(self):
        print("内存加载完成")
    
    def clear(self):
        print("内存清空")

# 1. 子系统类3:硬盘
class HardDisk:
    def read(self):
        print("硬盘读取数据")
    
    def write(self):
        print("硬盘写入数据")

# 1. 子系统类4:显示器
class Monitor:
    def turn_on(self):
        print("显示器开机")
    
    def turn_off(self):
        print("显示器关机")

# 2. 外观类:电脑外观
class ComputerFacade:
    def __init__(self):
        self.cpu = CPU()
        self.memory = Memory()
        self.hard_disk = HardDisk()
        self.monitor = Monitor()
    
    # 统一的开机接口
    def startup(self):
        print("=== 开始开机 ===")
        self.cpu.start()
        self.memory.load()
        self.hard_disk.read()
        self.monitor.turn_on()
        print("=== 开机完成 ===")
    
    # 统一的关机接口
    def shutdown(self):
        print("=== 开始关机 ===")
        self.monitor.turn_off()
        self.hard_disk.write()
        self.memory.clear()
        self.cpu.shutdown()
        print("=== 关机完成 ===")

# 客户端代码
if __name__ == "__main__":
    # 客户端仅依赖外观类,无需了解子系统的细节
    computer = ComputerFacade()
    computer.startup()  # 输出:
                        # === 开始开机 ===
                        # CPU开始运行
                        # 内存加载完成
                        # 硬盘读取数据
                        # 显示器开机
                        # === 开机完成 ===
    
    computer.shutdown()  # 输出:
                         # === 开始关机 ===
                         # 显示器关机
                         # 硬盘写入数据
                         # 内存清空
                         # CPU停止运行
                         # === 关机完成 ===
应用场景
  • 当需要简化复杂子系统的使用时;
  • 当需要降低客户端与子系统的耦合度时;
  • 当需要为子系统提供统一入口时(如 API 网关)。

3.6 享元模式(Flyweight Pattern)

现实类比:围棋棋盘

围棋棋盘有 361 个交叉点,每个交叉点可以放置黑色或白色棋子。若为每个交叉点创建一个 “棋子” 对象,会占用大量内存 —— 享元模式将 “棋子颜色”(内部状态)与 “位置”(外部状态)分离,相同颜色的棋子共享一个对象。

核心问题:共享对象以减少内存消耗,适用于 “大量相似对象” 的场景。

享元模式的关键是内部状态与外部状态的分离

  • 内部状态:对象可共享的不变部分(如棋子颜色);
  • 外部状态:对象随环境变化的可变部分(如棋子位置)。
实现步骤
  1. 定义享元类:包含内部状态(如Chessmancolor);
  2. 定义享元工厂:管理享元对象,确保相同内部状态的对象仅创建一个;
  3. 客户端通过享元工厂获取享元对象,并传入外部状态(如位置)。
Python 代码示例
# 1. 享元类:围棋棋子
class Chessman:
    def __init__(self, color: str):
        self._color = color  # 内部状态:颜色(可共享)
    
    def show(self, position: tuple):
        # position:外部状态(不可共享,由客户端传入)
        print(f"棋子颜色:{self._color},位置:{position}")

# 2. 享元工厂:棋子工厂
class ChessmanFactory:
    _chessmen = {}  # 缓存享元对象
    
    @classmethod
    def get_chessman(cls, color: str):
        # 若缓存中不存在,创建并缓存;否则直接返回
        if color not in cls._chessmen:
            cls._chessmen[color] = Chessman(color)
        return cls._chessmen[color]

# 客户端代码
if __name__ == "__main__":
    # 获取黑色棋子享元对象
    black_chessman1 = ChessmanFactory.get_chessman("黑色")
    black_chessman2 = ChessmanFactory.get_chessman("黑色")
    print(f"黑色棋子是否为同一对象:{black_chessman1 is black_chessman2}")  # 输出:True
    
    # 获取白色棋子享元对象
    white_chessman1 = ChessmanFactory.get_chessman("白色")
    white_chessman2 = ChessmanFactory.get_chessman("白色")
    print(f"白色棋子是否为同一对象:{white_chessman1 is white_chessman2}")  # 输出:True
    
    # 显示棋子(传入外部状态位置)
    black_chessman1.show((1, 2))  # 输出:棋子颜色:黑色,位置:(1, 2)
    black_chessman2.show((3, 4))  # 输出:棋子颜色:黑色,位置:(3, 4)
    white_chessman1.show((5, 6))  # 输出:棋子颜色:白色,位置:(5, 6)
    white_chessman2.show((7, 8))  # 输出:棋子颜色:白色,位置:(7, 8)
应用场景
  • 当需要创建大量相似对象(如文字、图标、棋子)时;
  • 当对象的内部状态占比高,外部状态可由客户端传入时;
  • 当需要减少内存消耗时(如游戏开发、GUI 界面)。

3.7 代理模式(Proxy Pattern)

现实类比:代理服务器

用户访问国外网站时,会通过代理服务器转发请求 —— 代理服务器与国外网站通信,将响应返回给用户。代理模式为对象提供一个 “代理”,控制对原对象的访问。

核心问题:为另一个对象提供代理,以控制对原对象的访问(如权限控制、延迟加载、日志记录)。
代理模式的类型
  1. 静态代理:编译时就确定代理类;
  2. 动态代理:运行时动态生成代理类(如 Python 的functools.wraps、Java 的Proxy);
  3. 虚拟代理:延迟加载原对象(如大图片加载前先显示占位符);
  4. 保护代理:控制原对象的访问权限;
  5. 远程代理:代理远程对象(如 RPC 调用)。
Python 代码示例:静态代理(日志记录)
# 1. 业务接口:用户服务
class UserService:
    def create_user(self, username: str):
        pass
    
    def get_user(self, user_id: int):
        pass

# 2. 具体业务类:用户服务实现
class UserServiceImpl(UserService):
    def create_user(self, username: str):
        print(f"创建用户:{username}")
    
    def get_user(self, user_id: int):
        print(f"获取用户:{user_id}")

# 3. 代理类:用户服务代理(添加日志记录功能)
class UserServiceProxy(UserService):
    def __init__(self, user_service: UserService):
        self._user_service = user_service  # 组合具体业务对象
    
    def create_user(self, username: str):
        # 代理逻辑:日志记录
        print(f"【日志】开始调用create_user,参数:username={username}")
        # 调用原对象的方法
        self._user_service.create_user(username)
        print(f"【日志】结束调用create_user")
    
    def get_user(self, user_id: int):
        print(f"【日志】开始调用get_user,参数:user_id={user_id}")
        self._user_service.get_user(user_id)
        print(f"【日志】结束调用get_user")

# 客户端代码
if __name__ == "__main__":
    # 创建具体业务对象
    user_service = UserServiceImpl()
    # 创建代理对象
    proxy = UserServiceProxy(user_service)
    # 通过代理对象调用业务方法
    proxy.create_user("张三")  # 输出:
                               # 【日志】开始调用create_user,参数:username=张三
                               # 创建用户:张三
                               # 【日志】结束调用create_user
    
    proxy.get_user(1)  # 输出:
                       # 【日志】开始调用get_user,参数:user_id=1
                       # 获取用户:1
                       # 【日志】结束调用get_user
应用场景
  • 当需要控制对原对象的访问权限时;
  • 当需要为原对象添加额外功能(如日志、缓存)时;
  • 当需要延迟加载原对象(如大文件、数据库查询)时;
  • 当需要代理远程对象(如 RPC、API 调用)时。

四、行为型模式详解

行为型模式的本质是 “定义对象间的通信规则与职责分配”,解决 “对象如何交互” 的问题。它关注的是对象的 “行为” 和 “协作”。

4.1 责任链模式(Chain of Responsibility Pattern)

现实类比:公司审批流程

员工请假需要经过组长→部门经理→CEO 的审批:组长可审批 1 天以内的请假,部门经理可审批 3 天以内的请假,CEO 可审批 10 天以内的请假。若审批人无权审批,则自动将请求传递给下一个审批人。

核心问题:将请求的发送者与接收者解耦,让多个接收者都有机会处理请求,请求沿着 “责任链” 依次传递,直到被处理。
实现步骤
  1. 定义请求类:包含请求的信息(如LeaveRequestdaysreason);
  2. 定义抽象处理者类:规范处理请求的方法(如Approverapprove()),并维护下一个处理者的引用;
  3. 定义具体处理者类:如TeamLeaderDepartmentManagerCEO,实现处理请求的逻辑,若无法处理则传递给下一个处理者。
Python 代码示例
# 1. 请求类:请假请求
class LeaveRequest:
    def __init__(self, days: int, reason: str):
        self.days = days  # 请假天数
        self.reason = reason  # 请假理由

# 2. 抽象处理者类:审批人
class Approver:
    def __init__(self, name: str):
        self.name = name
        self._next_approver = None  # 下一个审批人
    
    # 设置下一个审批人
    def set_next(self, approver):
        self._next_approver = approver
        return self  # 链式调用
    
    # 处理请假请求
    def approve(self, request: LeaveRequest):
        pass

# 3. 具体处理者类1:组长(可审批1天以内)
class TeamLeader(Approver):
    def approve(self, request: LeaveRequest):
        if request.days <= 1:
            print(f"组长{self.name}审批通过请假:{request.days}天,理由:{request.reason}")
        elif self._next_approver:
            print(f"组长{self.name}无权审批,转交给下一个审批人")
            self._next_approver.approve(request)
        else:
            print(f"请假请求无人审批")

# 3. 具体处理者类2:部门经理(可审批3天以内)
class DepartmentManager(Approver):
    def approve(self, request: LeaveRequest):
        if request.days <= 3:
            print(f"部门经理{self.name}审批通过请假:{request.days}天,理由:{request.reason}")
        elif self._next_approver:
            print(f"部门经理{self.name}无权审批,转交给下一个审批人")
            self._next_approver.approve(request)
        else:
            print(f"请假请求无人审批")

# 3. 具体处理者类3:CEO(可审批10天以内)
class CEO(Approver):
    def approve(self, request: LeaveRequest):
        if request.days <= 10:
            print(f"CEO{self.name}审批通过请假:{request.days}天,理由:{request.reason}")
        else:
            print(f"CEO{self.name}拒绝审批请假:{request.days}天,理由:超过最大请假天数")

# 客户端代码
if __name__ == "__main__":
    # 创建审批人
    team_leader = TeamLeader("张三")
    department_manager = DepartmentManager("李四")
    ceo = CEO("王五")
    
    # 构建责任链:组长→部门经理→CEO
    team_leader.set_next(department_manager).set_next(ceo)
    
    # 测试1:请假0.5天(组长审批)
    request1 = LeaveRequest(0.5, "感冒")
    print("\n=== 请假请求1 ===")
    team_leader.approve(request1)  # 输出:组长张三审批通过请假:0.5天,理由:感冒
    
    # 测试2:请假2天(部门经理审批)
    request2 = LeaveRequest(2, "家中有事")
    print("\n=== 请假请求2 ===")
    team_leader.approve(request2)  # 输出:组长张三无权审批,转交给下一个审批人;部门经理李四审批通过请假:2天,理由:家中有事
    
    # 测试3:请假5天(CEO审批)
    request3 = LeaveRequest(5, "探亲")
    print("\n=== 请假请求3 ===")
    team_leader.approve(request3)  # 输出:组长张三无权审批;部门经理李四无权审批;CEO王五审批通过请假:5天,理由:探亲
    
    # 测试4:请假15天(CEO拒绝)
    request4 = LeaveRequest(15, "旅游")
    print("\n=== 请假请求4 ===")
    team_leader.approve(request4)  # 输出:CEO王五拒绝审批请假:15天,理由:超过最大请假天数
应用场景
  • 当需要多个对象处理同一请求时;
  • 当需要动态组合处理者时;
  • 当需要请求的发送者与接收者解耦时(如审批流程、日志级别过滤、异常处理)。

4.2 命令模式(Command Pattern)

现实类比:遥控器

电视遥控器上的每个按钮对应一个 “命令”(如开、关、音量 +、音量 -),当用户按下按钮时,遥控器将命令发送给电视执行。命令模式将 “请求” 封装为对象,让请求的发送者与执行者解耦。

核心问题:将请求封装为对象,允许参数化请求(如不同的命令)、队列请求(如命令历史)、撤销请求(如撤销操作)。
实现步骤
  1. 定义命令接口:规范命令的执行方法(如Commandexecute());
  2. 定义具体命令类:如TurnOnCommandTurnOffCommand,实现命令接口,并组合接收者对象;
  3. 定义接收者类:如TV,实现具体的业务逻辑(如turn_on()turn_off());
  4. 定义请求者类:如RemoteControl,维护命令对象,并调用命令的execute()方法。
Python 代码示例
# 1. 接收者类:电视
class TV:
    def turn_on(self):
        print("电视已打开")
    
    def turn_off(self):
        print("电视已关闭")
    
    def volume_up(self):
        print("音量+")
    
    def volume_down(self):
        print("音量-")

# 2. 命令接口
class Command:
    def execute(self):
        pass
    
    def undo(self):
        pass  # 可选:撤销命令

# 3. 具体命令类1:打开电视
class TurnOnCommand(Command):
    def __init__(self, tv: TV):
        self._tv = tv  # 组合接收者对象
    
    def execute(self):
        self._tv.turn_on()
    
    def undo(self):
        self._tv.turn_off()  # 撤销打开命令:关闭电视

# 3. 具体命令类2:关闭电视
class TurnOffCommand(Command):
    def __init__(self, tv: TV):
        self._tv = tv
    
    def execute(self):
        self._tv.turn_off()
    
    def undo(self):
        self._tv.turn_on()  # 撤销关闭命令:打开电视

# 3. 具体命令类3:音量+
class VolumeUpCommand(Command):
    def __init__(self, tv: TV):
        self._tv = tv
    
    def execute(self):
        self._tv.volume_up()
    
    def undo(self):
        self._tv.volume_down()  # 撤销音量+:音量-

# 4. 请求者类:遥控器
class RemoteControl:
    def __init__(self):
        self._command = None  # 当前命令
        self._history = []  # 命令历史,用于撤销
    
    # 设置当前命令
    def set_command(self, command: Command):
        self._command = command
    
    # 执行当前命令
    def press_button(self):
        if self._command:
            self._command.execute()
            self._history.append(self._command)  # 记录命令历史
    
    # 撤销最后一个命令
    def press_undo(self):
        if self._history:
            last_command = self._history.pop()
            last_command.undo()

# 客户端代码
if __name__ == "__main__":
    # 创建接收者
    tv = TV()
    
    # 创建命令
    turn_on_cmd = TurnOnCommand(tv)
    turn_off_cmd = TurnOffCommand(tv)
    volume_up_cmd = VolumeUpCommand(tv)
    
    # 创建请求者
    remote = RemoteControl()
    
    # 测试打开电视
    print("\n=== 按下打开按钮 ===")
    remote.set_command(turn_on_cmd)
    remote.press_button()  # 输出:电视已打开
    
    # 测试音量+
    print("\n=== 按下音量+按钮 ===")
    remote.set_command(volume_up_cmd)
    remote.press_button()  # 输出:音量+
    remote.press_button()  # 输出:音量+
    
    # 测试撤销
    print("\n=== 按下撤销按钮 ===")
    remote.press_undo()  # 输出:音量-
    remote.press_undo()  # 输出:音量-
    
    # 测试关闭电视
    print("\n=== 按下关闭按钮 ===")
    remote.set_command(turn_off_cmd)
    remote.press_button()  # 输出:电视已关闭
    
    # 测试撤销关闭
    print("\n=== 按下撤销按钮 ===")
    remote.press_undo()  # 输出:电视已打开
应用场景
  • 当需要将请求的发送者与执行者解耦时;
  • 当需要支持命令队列(如任务调度)时;
  • 当需要支持撤销 / 重做操作时(如编辑器、游戏);
  • 当需要记录命令历史(如审计日志)时。

4.3 迭代器模式(Iterator Pattern)

现实类比:图书馆书架

图书馆的书架上有很多书,用户不需要知道书的排列方式,只需要通过 “迭代器” 依次获取每一本书。迭代器模式提供一种遍历集合对象元素的统一方式,无需暴露集合的内部结构。

核心问题:提供一种遍历集合对象元素的统一接口,与集合的具体实现无关。
实现步骤
  1. 定义迭代器接口:规范遍历的方法(如Iteratorhas_next()next());
  2. 定义具体迭代器类:如BookShelfIterator,实现迭代器接口,维护遍历的当前位置;
  3. 定义集合接口:规范集合的方法(如Aggregatecreate_iterator());
  4. 定义具体集合类:如BookShelf,实现集合接口,创建并返回具体迭代器。
Python 代码示例
# 1. 迭代器接口
class Iterator:
    def has_next(self) -> bool:
        # 是否还有下一个元素
        pass
    
    def next(self):
        # 返回下一个元素
        pass

# 2. 集合接口(聚合接口)
class Aggregate:
    def create_iterator(self) -> Iterator:
        # 创建迭代器
        pass

# 3. 具体集合类:书架
class BookShelf(Aggregate):
    def __init__(self):
        self._books = []  # 内部存储结构
    
    def add_book(self, book: str):
        self._books.append(book)
    
    def get_book(self, index: int) -> str:
        return self._books[index]
    
    def size(self) -> int:
        return len(self._books)
    
    def create_iterator(self) -> Iterator:
        return BookShelfIterator(self)

# 4. 具体迭代器类:书架迭代器
class BookShelfIterator(Iterator):
    def __init__(self, book_shelf: BookShelf):
        self._book_shelf = book_shelf
        self._index = 0  # 当前遍历位置
    
    def has_next(self) -> bool:
        return self._index < self._book_shelf.size()
    
    def next(self):
        if self.has_next():
            book = self._book_shelf.get_book(self._index)
            self._index += 1
            return book
        return None

# 客户端代码
if __name__ == "__main__":
    # 创建书架
    book_shelf = BookShelf()
    book_shelf.add_book("设计模式")
    book_shelf.add_book("Python编程")
    book_shelf.add_book("算法导论")
    
    # 获取迭代器
    iterator = book_shelf.create_iterator()
    
    # 遍历集合
    print("书架上的书:")
    while iterator.has_next():
        book = iterator.next()
        print(f"  - {book}")  # 输出:设计模式、Python编程、算法导论
应用场景
  • 当需要遍历集合对象但不暴露其内部结构时;
  • 当需要为不同的集合提供统一的遍历接口时;
  • 当需要在遍历过程中修改集合时(如安全遍历)。
注意:Python 中的迭代器

Python 内置支持迭代器模式,通过__iter__()__next__()方法实现。例如,上述BookShelf类可直接实现__iter__()方法:

class BookShelf:
    def __init__(self):
        self._books = []
    
    def add_book(self, book: str):
        self._books.append(book)
    
    def __iter__(self):
        # 返回迭代器对象
        return iter(self._books)

# 客户端代码
book_shelf = BookShelf()
book_shelf.add_book("设计模式")
for book in book_shelf:
    print(book)  # 输出:设计模式

4.4 中介者模式(Mediator Pattern)

现实类比:机场塔台

飞机在机场起降时,不会直接与其他飞机通信,而是通过塔台(中介者)协调 —— 塔台告诉飞机何时起降、如何滑行,避免飞机之间的直接耦合。

核心问题:减少对象间的直接通信,通过中介者集中管理对象间的交互,降低系统的耦合度。
实现步骤
  1. 定义中介者接口:规范中介者的方法(如Mediatornotify());
  2. 定义具体中介者类:如AirTrafficControl,维护所有同事对象的引用,并处理它们的交互;
  3. 定义同事类:如Airplane,包含中介者的引用,当需要与其他同事通信时,通过中介者。
Python 代码示例
# 1. 中介者接口
class Mediator:
    def notify(self, sender: "Colleague", message: str):
        pass

# 2. 同事类(抽象)
class Colleague:
    def __init__(self, mediator: Mediator, name: str):
        self._mediator = mediator
        self._name = name
    
    def send(self, message: str):
        # 通过中介者发送消息
        print(f"{self._name}发送消息:{message}")
        self._mediator.notify(self, message)
    
    def receive(self, message: str):
        # 接收消息
        print(f"{self._name}接收消息:{message}")

# 3. 具体同事类:飞机
class Airplane(Colleague):
    pass

# 4. 具体中介者类:空中交通管制(塔台)
class AirTrafficControl(Mediator):
    def __init__(self):
        self._planes = []  # 维护所有飞机的引用
    
    def add_plane(self, plane: Airplane):
        self._planes.append(plane)
    
    def notify(self, sender: Colleague, message: str):
        # 中介者处理消息:将消息转发给所有其他飞机
        for plane in self._planes:
            if plane != sender:
                plane.receive(message)

# 客户端代码
if __name__ == "__main__":
    # 创建中介者
    atc = AirTrafficControl()
    
    # 创建同事对象(飞机)
    plane1 = Airplane(atc, "飞机1")
    plane2 = Airplane(atc, "飞机2")
    plane3 = Airplane(atc, "飞机3")
    
    # 注册飞机到中介者
    atc.add_plane(plane1)
    atc.add_plane(plane2)
    atc.add_plane(plane3)
    
    # 飞机1发送消息
    print("\n=== 飞机1发送起飞请求 ===")
    plane1.send("请求起飞")  # 输出:
                             # 飞机1发送消息:请求起飞
                             # 飞机2接收消息:请求起飞
                             # 飞机3接收消息:请求起飞
    
    # 飞机2发送消息
    print("\n=== 飞机2发送降落请求 ===")
    plane2.send("请求降落")  # 输出:
                             # 飞机2发送消息:请求降落
                             # 飞机1接收消息:请求降落
                             # 飞机3接收消息:请求降落
应用场景
  • 对象间的通信复杂且多对多时;
  • 当需要降低对象间的耦合度时;
  • 当需要集中管理对象间的交互时(如聊天室、GUI 组件通信、分布式系统)。

4.5 备忘录模式(Memento Pattern)

现实类比:游戏存档

玩游戏时,玩家会定期存档 —— 存档包含当前游戏的进度(关卡、生命值、装备等),当玩家失败时可以读档恢复到之前的状态。备忘录模式用于保存对象的内部状态,并在需要时恢复,且不会暴露对象的内部结构。

核心问题:保存对象的内部状态,在不暴露对象内部结构的前提下,允许在需要时恢复到之前的状态。
实现步骤
  1. 定义备忘录类:如Memento,保存发起人的内部状态;
  2. 定义发起人类:如Game,创建备忘录(保存状态)并从备忘录恢复状态;
  3. 定义负责人类:如GameCaretaker,管理备忘录对象(如存档列表)。
Python 代码示例
# 1. 备忘录类:游戏存档
class Memento:
    def __init__(self, level: int, hp: int, equipment: list):
        # 保存发起人的内部状态(关卡、生命值、装备)
        self._level = level
        self._hp = hp
        self._equipment = equipment.copy()  # 深拷贝,避免引用问题
    
    # 仅提供状态的读取方法,不提供修改方法
    def get_level(self):
        return self._level
    
    def get_hp(self):
        return self._hp
    
    def get_equipment(self):
        return self._equipment

# 2. 发起人类:游戏
class Game:
    def __init__(self):
        self._level = 1
        self._hp = 100
        self._equipment = []
    
    # 更新游戏状态
    def progress(self, level_up: bool, hp_change: int, new_equipment: str = None):
        if level_up:
            self._level += 1
            print(f"关卡提升到:{self._level}")
        self._hp += hp_change
        print(f"生命值变化为:{self._hp}")
        if new_equipment:
            self._equipment.append(new_equipment)
            print(f"获得装备:{new_equipment}")
    
    # 创建备忘录:保存当前状态
    def create_memento(self) -> Memento:
        return Memento(self._level, self._hp, self._equipment)
    
    # 从备忘录恢复状态
    def restore_from_memento(self, memento: Memento):
        self._level = memento.get_level()
        self._hp = memento.get_hp()
        self._equipment = memento.get_equipment()
        print(f"游戏状态恢复完成:关卡={self._level},生命值={self._hp},装备={self._equipment}")

# 3. 负责人类:游戏存档管理器
class GameCaretaker:
    def __init__(self):
        self._mementos = []  # 保存所有存档
    
    # 保存存档
    def save_memento(self, memento: Memento):
        self._mementos.append(memento)
        print(f"存档已保存,当前存档数量:{len(self._mementos)}")
    
    # 读取指定索引的存档
    def get_memento(self, index: int) -> Memento:
        if 0 <= index < len(self._mementos):
            return self._mementos[index]
        return None

# 客户端代码
if __name__ == "__main__":
    # 创建游戏
    game = Game()
    # 创建存档管理器
    caretaker = GameCaretaker()
    
    # 游戏进度1:关卡1,生命值100,无装备
    print("\n=== 游戏进度1 ===")
    game.progress(False, 0)
    caretaker.save_memento(game.create_memento())  # 存档
    
    # 游戏进度2:关卡2,生命值80,获得剑
    print("\n=== 游戏进度2 ===")
    game.progress(True, -20, "剑")
    caretaker.save_memento(game.create_memento())  # 存档
    
    # 游戏进度3:关卡2,生命值50,获得盾
    print("\n=== 游戏进度3 ===")
    game.progress(False, -30, "盾")
    
    # 恢复到存档1
    print("\n=== 恢复到存档1 ===")
    memento1 = caretaker.get_memento(0)
    game.restore_from_memento(memento1)  # 输出:游戏状态恢复完成:关卡=1,生命值=100,装备=[]
    
    # 恢复到存档2
    print("\n=== 恢复到存档2 ===")
    memento2 = caretaker.get_memento(1)
    game.restore_from_memento(memento2)  # 输出:游戏状态恢复完成:关卡=2,生命值=80,装备=['剑']
应用场景
  • 当需要保存和恢复对象的状态时(如编辑器的撤销 / 重做、游戏存档、数据库事务回滚);
  • 当需要避免暴露对象的内部结构时;
  • 当需要记录对象的历史状态时。

4.6 观察者模式(Observer Pattern)

现实类比:公众号订阅

用户订阅公众号后,公众号发布新文章时会自动通知所有订阅者。观察者模式定义了一对多的依赖关系,当一个对象(主题)的状态变化时,所有依赖它的对象(观察者)都会自动收到通知并更新。

核心问题:实现对象间的自动通知机制,当主题状态变化时,所有观察者自动更新,无需主题主动调用。
实现步骤
  1. 定义主题接口:规范主题的方法(如Subjectregister_observer()remove_observer()notify_observers());
  2. 定义具体主题类:如WeatherStation,维护观察者列表,并在状态变化时通知所有观察者;
  3. 定义观察者接口:规范观察者的方法(如Observerupdate());
  4. 定义具体观察者类:如PhoneDisplayPCDisplay,实现update()方法,处理主题的通知。
Python 代码示例
# 1. 主题接口
class Subject:
    def __init__(self):
        self._observers = []  # 观察者列表
    
    # 注册观察者
    def register_observer(self, observer):
        if observer not in self._observers:
            self._observers.append(observer)
    
    # 移除观察者
    def remove_observer(self, observer):
        if observer in self._observers:
            self._observers.remove(observer)
    
    # 通知所有观察者
    def notify_observers(self):
        for observer in self._observers:
            observer.update()

# 2. 具体主题类:气象站
class WeatherStation(Subject):
    def __init__(self):
        super().__init__()
        self._temperature = 0.0  # 温度(主题状态)
    
    # 获取温度
    def get_temperature(self):
        return self._temperature
    
    # 设置温度:状态变化时通知观察者
    def set_temperature(self, temperature: float):
        self._temperature = temperature
        print(f"气象站:温度更新为{temperature}°C")
        self.notify_observers()  # 自动通知所有观察者

# 3. 观察者接口
class Observer:
    def update(self):
        pass

# 4. 具体观察者类1:手机显示器
class PhoneDisplay(Observer):
    def __init__(self, weather_station: WeatherStation):
        self._weather_station = weather_station
    
    def update(self):
        temperature = self._weather_station.get_temperature()
        print(f"手机显示器:当前温度是{temperature}°C")

# 4. 具体观察者类2:电脑显示器
class PCDisplay(Observer):
    def __init__(self, weather_station: WeatherStation):
        self._weather_station = weather_station
    
    def update(self):
        temperature = self._weather_station.get_temperature()
        print(f"电脑显示器:当前温度是{temperature}°C")

# 客户端代码
if __name__ == "__main__":
    # 创建主题
    weather_station = WeatherStation()
    
    # 创建观察者
    phone_display = PhoneDisplay(weather_station)
    pc_display = PCDisplay(weather_station)
    
    # 注册观察者
    weather_station.register_observer(phone_display)
    weather_station.register_observer(pc_display)
    
    # 测试温度变化
    print("\n=== 温度变化1:25°C ===")
    weather_station.set_temperature(25.0)  # 输出:
                                            # 气象站:温度更新为25.0°C
                                            # 手机显示器:当前温度是25.0°C
                                            # 电脑显示器:当前温度是25.0°C
    
    # 移除观察者(手机显示器)
    weather_station.remove_observer(phone_display)
    
    print("\n=== 温度变化2:30°C ===")
    weather_station.set_temperature(30.0)  # 输出:
                                            # 气象站:温度更新为30.0°C
                                            # 电脑显示器:当前温度是30.0°C
应用场景
  • 当需要一对多的依赖关系时(如订阅 - 发布、监控系统、事件驱动架构);
  • 当需要对象间的自动通知时;
  • 当需要低耦合的通信机制时。

4.7 状态模式(State Pattern)

现实类比:交通信号灯

交通信号灯有红、黄、绿三种状态,每种状态下的行为不同(红灯停、绿灯行、黄灯警告),且状态之间可以自动切换(绿→黄→红→绿...)。状态模式将对象的状态封装为独立的类,让对象在不同状态下表现出不同的行为。

核心问题:当对象的行为依赖于其状态,且状态可以动态变化时,将状态封装为独立的类,避免使用大量的条件判断。
实现步骤
  1. 定义状态接口:规范状态的行为(如TrafficLightStateshow()next_state());
  2. 定义具体状态类:如RedStateYellowStateGreenState,实现状态接口的方法;
  3. 定义上下文类:如TrafficLight,维护当前状态对象,并将请求委托给当前状态。
Python 代码示例
# 1. 状态接口:交通信号灯状态
class TrafficLightState:
    def show(self):
        pass  # 显示当前状态
    
    def next_state(self, traffic_light):
        pass  # 切换到下一个状态

# 2. 具体状态类1:红灯
class RedState(TrafficLightState):
    def show(self):
        print("交通信号灯:红灯亮(禁止通行)")
    
    def next_state(self, traffic_light):
        traffic_light.set_state(YellowState())  # 红灯→黄灯

# 2. 具体状态类2:黄灯
class YellowState(TrafficLightState):
    def show(self):
        print("交通信号灯:黄灯亮(警告)")
    
    def next_state(self, traffic_light):
        traffic_light.set_state(GreenState())  # 黄灯→绿灯

# 2. 具体状态类3:绿灯
class GreenState(TrafficLightState):
    def show(self):
        print("交通信号灯:绿灯亮(可以通行)")
    
    def next_state(self, traffic_light):
        traffic_light.set_state(RedState())  # 绿灯→红灯

# 3. 上下文类:交通信号灯
class TrafficLight:
    def __init__(self):
        self._state = RedState()  # 初始状态为红灯
    
    # 设置当前状态
    def set_state(self, state: TrafficLightState):
        self._state = state
    
    # 显示当前状态
    def show(self):
        self._state.show()
    
    # 切换到下一个状态
    def next(self):
        self._state.next_state(self)

# 客户端代码
if __name__ == "__main__":
    traffic_light = TrafficLight()
    
    print("\n=== 信号灯状态1 ===")
    traffic_light.show()  # 输出:交通信号灯:红灯亮(禁止通行)
    
    print("\n=== 切换到下一个状态 ===")
    traffic_light.next()
    traffic_light.show()  # 输出:交通信号灯:黄灯亮(警告)
    
    print("\n=== 切换到下一个状态 ===")
    traffic_light.next()
    traffic_light.show()  # 输出:交通信号灯:绿灯亮(可以通行)
    
    print("\n=== 切换到下一个状态 ===")
    traffic_light.next()
    traffic_light.show()  # 输出:交通信号灯:红灯亮(禁止通行)
应用场景
  • 当对象的行为随状态变化时;
  • 当对象的状态数量较多,且状态之间可以动态切换时;
  • 当对象的条件判断语句过于复杂时(如大量的 if-elif-else 或 switch-case)。

4.8 策略模式(Strategy Pattern)

现实类比:支付方式

用户在电商平台购物时,可以选择支付宝、微信支付、银行卡支付等不同的支付方式 —— 每种支付方式的逻辑不同,但都是 “支付” 这个功能的实现。策略模式将不同的算法封装为独立的策略类,让客户端可以动态切换算法

核心问题:定义一系列算法,将它们封装为独立的策略类,让它们可以相互替换,且客户端与算法的具体实现解耦。
实现步骤
  1. 定义策略接口:规范算法的方法(如PaymentStrategypay());
  2. 定义具体策略类:如AlipayStrategyWechatPayStrategy,实现策略接口;
  3. 定义上下文类:如Order,维护策略对象,并委托策略类执行算法。
Python 代码示例
# 1. 策略接口:支付策略
class PaymentStrategy:
    def pay(self, amount: float):
        pass  # 支付逻辑

# 2. 具体策略类1:支付宝支付
class AlipayStrategy(PaymentStrategy):
    def pay(self, amount: float):
        print(f"使用支付宝支付:{amount}元")

# 2. 具体策略类2:微信支付
class WechatPayStrategy(PaymentStrategy):
    def pay(self, amount: float):
        print(f"使用微信支付:{amount}元")

# 2. 具体策略类3:银行卡支付
class BankCardPayStrategy(PaymentStrategy):
    def pay(self, amount: float):
        print(f"使用银行卡支付:{amount}元")

# 3. 上下文类:订单
class Order:
    def __init__(self, amount: float):
        self._amount = amount  # 订单金额
        self._payment_strategy = None  # 当前支付策略
    
    # 设置支付策略
    def set_payment_strategy(self, strategy: PaymentStrategy):
        self._payment_strategy = strategy
    
    # 执行支付
    def pay(self):
        if self._payment_strategy:
            self._payment_strategy.pay(self._amount)
        else:
            print("未选择支付方式")

# 客户端代码
if __name__ == "__main__":
    # 创建订单
    order = Order(100.0)
    
    # 使用支付宝支付
    print("\n=== 支付宝支付 ===")
    order.set_payment_strategy(AlipayStrategy())
    order.pay()  # 输出:使用支付宝支付:100.0元
    
    # 使用微信支付
    print("\n=== 微信支付 ===")
    order.set_payment_strategy(WechatPayStrategy())
    order.pay()  # 输出:使用微信支付:100.0元
    
    # 使用银行卡支付
    print("\n=== 银行卡支付 ===")
    order.set_payment_strategy(BankCardPayStrategy())
    order.pay()  # 输出:使用银行卡支付:100.0元
    
    # 新增支付方式仅需定义策略类,无需修改Order类
    # class ApplePayStrategy(PaymentStrategy): ...
    # order.set_payment_strategy(ApplePayStrategy())
    # order.pay()
应用场景
  • 当需要多种算法解决同一问题时;
  • 当需要动态切换算法时;
  • 当需要避免算法的硬编码时(如支付方式、排序算法、搜索算法)。

4.9 模板方法模式(Template Method Pattern)

现实类比:泡茶与泡咖啡

泡茶的步骤:烧水→放茶叶→冲泡→倒杯子;泡咖啡的步骤:烧水→放咖啡粉→冲泡→倒杯子。两者的核心步骤相同,但某些步骤的实现不同。模板方法模式将核心步骤定义为 “模板方法”,将可变步骤延迟到子类实现。

核心问题:定义算法的骨架,将可变部分延迟到子类实现,确保算法的结构不变,同时允许子类自定义某些步骤。
实现步骤
  1. 定义抽象类:规范算法的核心步骤(模板方法),并将可变步骤定义为抽象方法;
  2. 定义具体子类:实现抽象类中的可变步骤。
Python 代码示例
# 1. 抽象类:冲泡饮料
class Beverage:
    # 模板方法:定义算法的骨架(核心步骤)
    def prepare(self):
        self.boil_water()  # 烧水(固定步骤)
        self.add_ingredient()  # 加原料(可变步骤)
        self.brew()  # 冲泡(固定步骤)
        self.pour_in_cup()  # 倒杯子(固定步骤)
    
    # 固定步骤1:烧水
    def boil_water(self):
        print("烧水")
    
    # 可变步骤1:加原料(抽象方法,子类实现)
    def add_ingredient(self):
        pass
    
    # 固定步骤2:冲泡
    def brew(self):
        print("冲泡")
    
    # 固定步骤3:倒杯子
    def pour_in_cup(self):
        print("倒入杯子")

# 2. 具体子类1:泡茶
class Tea(Beverage):
    # 实现可变步骤:加茶叶
    def add_ingredient(self):
        print("加茶叶")

# 2. 具体子类2:泡咖啡
class Coffee(Beverage):
    # 实现可变步骤:加咖啡粉
    def add_ingredient(self):
        print("加咖啡粉")

# 客户端代码
if __name__ == "__main__":
    # 泡茶
    print("\n=== 泡茶 ===")
    tea = Tea()
    tea.prepare()  # 输出:
                   # 烧水
                   # 加茶叶
                   # 冲泡
                   # 倒入杯子
    
    # 泡咖啡
    print("\n=== 泡咖啡 ===")
    coffee = Coffee()
    coffee.prepare()  # 输出:
                      # 烧水
                      # 加咖啡粉
                      # 冲泡
                      # 倒入杯子
应用场景
  • 多个类的算法结构相似,只有部分步骤不同时;
  • 当需要确保算法的结构不变,同时允许子类自定义某些步骤时;
  • 当需要代码复用(固定步骤在抽象类中实现,无需子类重复编写)时。

4.10 访问者模式(Visitor Pattern)

现实类比:快递员配送

快递员需要配送不同类型的包裹(如文件、商品、易碎品),每种包裹的配送方式不同,但快递员(访问者)需要遍历所有包裹并执行配送。访问者模式用于在不修改集合元素类的前提下,为元素添加新的操作

核心问题:将数据结构操作数据的算法分离,允许动态扩展操作,而无需修改数据结构。
实现步骤
  1. 定义访问者接口:规范访问不同元素的方法(如Visitorvisit_document()visit_goods());
  2. 定义具体访问者类:如CourierVisitor,实现访问者接口的方法;
  3. 定义元素接口:规范元素的accept()方法(接收访问者);
  4. 定义具体元素类:如DocumentGoods,实现accept()方法,调用访问者的对应方法;
  5. 定义对象结构:如ParcelList,维护元素列表,并提供遍历方法。
Python 代码示例
# 1. 访问者接口
class Visitor:
    def visit_document(self, document: "Document"):
        pass
    
    def visit_goods(self, goods: "Goods"):
        pass

# 2. 具体访问者类:快递员
class CourierVisitor(Visitor):
    def visit_document(self, document: "Document"):
        print(f"配送文件包裹:{document.name},重量:{document.weight}kg")
    
    def visit_goods(self, goods: "Goods"):
        print(f"配送商品包裹:{goods.name},重量:{goods.weight}kg")

# 3. 元素接口
class Parcel:
    def accept(self, visitor: Visitor):
        pass

# 4. 具体元素类1:文件包裹
class Document(Parcel):
    def __init__(self, name: str, weight: float):
        self.name = name
        self.weight = weight
    
    def accept(self, visitor: Visitor):
        visitor.visit_document(self)  # 调用访问者的对应方法

# 4. 具体元素类2:商品包裹
class Goods(Parcel):
    def __init__(self, name: str, weight: float):
        self.name = name
        self.weight = weight
    
    def accept(self, visitor: Visitor):
        visitor.visit_goods(self)  # 调用访问者的对应方法

# 5. 对象结构:包裹列表
class ParcelList:
    def __init__(self):
        self._parcels = []
    
    def add_parcel(self, parcel: Parcel):
        self._parcels.append(parcel)
    
    # 遍历所有包裹,接受访问者访问
    def accept(self, visitor: Visitor):
        for parcel in self._parcels:
            parcel.accept(visitor)

# 客户端代码
if __name__ == "__main__":
    # 创建包裹列表
    parcel_list = ParcelList()
    
    # 添加包裹
    parcel_list.add_parcel(Document("合同文档", 0.5))
    parcel_list.add_parcel(Goods("手机", 0.3))
    parcel_list.add_parcel(Document("会议纪要", 0.2))
    
    # 创建访问者(快递员)
    courier = CourierVisitor()
    
    # 遍历包裹并配送
    print("\n=== 快递员开始配送 ===")
    parcel_list.accept(courier)  # 输出:
                                 # 配送文件包裹:合同文档,重量:0.5kg
                                 # 配送商品包裹:手机,重量:0.3kg
                                 # 配送文件包裹:会议纪要,重量:0.2kg
    
    # 新增访问者(如仓库管理员)仅需定义Visitor子类,无需修改Parcel或ParcelList类
    # class WarehouseVisitor(Visitor): ...
    # warehouse_visitor = WarehouseVisitor()
    # parcel_list.accept(warehouse_visitor)
应用场景
  • 当需要为数据结构添加新的操作,但又不想修改数据结构的类时;
  • 数据结构稳定,但操作需要频繁扩展时;
  • 当需要遍历复杂数据结构并执行不同操作时。

4.11 解释器模式(Interpreter Pattern)

现实类比:计算器

计算器可以解释并执行数学表达式(如 “1+2*3”)。解释器模式用于定义一种语言的文法,并创建一个解释器来解释该语言的表达式。

核心问题:定义简单语言的文法,并实现解释器来解析和执行该语言的表达式。
实现步骤
  1. 定义抽象表达式类:规范解释的方法(如Expressioninterpret());
  2. 定义终结符表达式类:如NumberExpression(数字),实现解释方法;
  3. 定义非终结符表达式类:如AddExpression(加法)、MultiplyExpression(乘法),实现解释方法;
  4. 客户端构建抽象语法树(AST),并调用根节点的interpret()方法。
Python 代码示例:简单计算器
# 1. 抽象表达式类
class Expression:
    def interpret(self) -> float:
        pass

# 2. 终结符表达式类:数字
class NumberExpression(Expression):
    def __init__(self, value: float):
        self._value = value
    
    def interpret(self) -> float:
        return self._value

# 3. 非终结符表达式类:加法
class AddExpression(Expression):
    def __init__(self, left: Expression, right: Expression):
        self._left = left  # 左操作数
        self._right = right  # 右操作数
    
    def interpret(self) -> float:
        return self._left.interpret() + self._right.interpret()

# 3. 非终结符表达式类:乘法
class MultiplyExpression(Expression):
    def __init__(self, left: Expression, right: Expression):
        self._left = left
        self._right = right
    
    def interpret(self) -> float:
        return self._left.interpret() * self._right.interpret()

# 客户端代码
if __name__ == "__main__":
    # 构建抽象语法树:1 + 2 * 3
    # 先构建乘法表达式:2 * 3
    multiply_expr = MultiplyExpression(NumberExpression(2.0), NumberExpression(3.0))
    # 再构建加法表达式:1 + (2 * 3)
    add_expr = AddExpression(NumberExpression(1.0), multiply_expr)
    
    # 解释并执行表达式
    result = add_expr.interpret()
    print(f"1 + 2 * 3 = {result}")  # 输出:7.0
    
    # 构建另一个表达式:(1 + 2) * 3
    add_expr2 = AddExpression(NumberExpression(1.0), NumberExpression(2.0))
    multiply_expr2 = MultiplyExpression(add_expr2, NumberExpression(3.0))
    result2 = multiply_expr2.interpret()
    print(f"(1 + 2) * 3 = {result2}")  # 输出:9.0
应用场景
  • 当需要解析简单语言或表达式时(如计算器、正则表达式、配置文件解析);
  • 文法规则简单时;
  • 当需要扩展语言的文法时。

五、J2EE 设计模式详解

J2EE 设计模式是针对 Java 企业级开发场景(如分层架构、分布式通信、资源管理)提炼的通用解决方案。虽然其名称基于 Java EE,但核心思想可应用于所有企业级开发语言(如 Python、Java、Go)。

5.1 MVC 模式(Model-View-Controller)

核心思想:分离关注点,将应用分为三个部分:
  • Model:数据层,负责数据的存储、获取和业务逻辑(如数据库操作、用户认证);
  • View:视图层,负责数据的展示(如 HTML 页面、API 响应);
  • Controller:控制器层,负责接收请求、调用 Model 处理数据、传递结果给 View 渲染。
Python 代码示例(基于 Flask 框架简化版)
# Model层:用户数据模型
class User:
    def __init__(self, id: int, name: str, email: str):
        self.id = id
        self.name = name
        self.email = email

# Model层:用户业务逻辑
class UserModel:
    def __init__(self):
        # 模拟数据库
        self._users = [
            User(1, "张三", "zhangsan@example.com"),
            User(2, "李四", "lisi@example.com")
        ]
    
    def get_user_by_id(self, user_id: int) -> User:
        for user in self._users:
            if user.id == user_id:
                return user
        return None

# View层:HTML视图模板(模拟)
class UserView:
    def render(self, user: User) -> str:
        return f"""
        <html>
            <body>
                <h1>用户信息</h1>
                <p>ID: {user.id}</p>
                <p>姓名: {user.name}</p>
                <p>邮箱: {user.email}</p>
            </body>
        </html>
        """

# Controller层:用户控制器
class UserController:
    def __init__(self, user_model: UserModel, user_view: UserView):
        self._user_model = user_model
        self._user_view = user_view
    
    # 处理用户查询请求
    def handle_user_request(self, user_id: int) -> str:
        # 1. 调用Model获取数据
        user = self._user_model.get_user_by_id(user_id)
        if user is None:
            return "<h1>用户不存在</h1>"
        # 2. 调用View渲染数据
        return self._user_view.render(user)

# 客户端代码(模拟Flask路由)
if __name__ == "__main__":
    # 初始化三层
    user_model = UserModel()
    user_view = UserView()
    user_controller = UserController(user_model, user_view)
    
    # 模拟请求:查询用户ID=1
    html = user_controller.handle_user_request(1)
    print(html)  # 输出用户1的HTML信息
    
    # 模拟请求:查询用户ID=3
    html = user_controller.handle_user_request(3)
    print(html)  # 输出用户不存在
应用场景
  • 所有分层架构的 Web 应用
  • 需要分离数据、业务逻辑和展示的应用;
  • 需要提高代码复用性和可维护性的应用。

5.2 数据访问对象模式(DAO Pattern)

核心思想:将数据访问逻辑业务逻辑分离,提供一个统一的接口(DAO)来访问不同的数据源(如数据库、文件、API)。
实现步骤
  1. 定义实体类:如User,对应数据源中的数据;
  2. 定义DAO 接口:规范数据访问的方法(如UserDAOsave()update()find_all());
  3. 定义具体 DAO 类:如MySQLUserDAOFileUserDAO,实现 DAO 接口,访问具体的数据源。
Python 代码示例
# 1. 实体类:用户
class User:
    def __init__(self, id: int, name: str):
        self.id = id
        self.name = name
    
    def __str__(self):
        return f"User(id={self.id}, name={self.name})"

# 2. DAO接口:用户数据访问
class UserDAO:
    def save(self, user: User):
        pass
    
    def find_by_id(self, user_id: int) -> User:
        pass
    
    def find_all(self) -> list:
        pass

# 3. 具体DAO类1:MySQL数据访问
class MySQLUserDAO(UserDAO):
    def save(self, user: User):
        print(f"MySQL: 保存用户 {user}")
    
    def find_by_id(self, user_id: int) -> User:
        print(f"MySQL: 查询用户ID={user_id}")
        return User(user_id, f"MySQL用户{user_id}")
    
    def find_all(self) -> list:
        print(f"MySQL: 查询所有用户")
        return [User(1, "MySQL用户1"), User(2, "MySQL用户2")]

# 3. 具体DAO类2:文件数据访问
class FileUserDAO(UserDAO):
    def save(self, user: User):
        print(f"File: 保存用户 {user} 到文件")
    
    def find_by_id(self, user_id: int) -> User:
        print(f"File: 从文件查询用户ID={user_id}")
        return User(user_id, f"File用户{user_id}")
    
    def find_all(self) -> list:
        print(f"File: 从文件查询所有用户")
        return [User(1, "File用户1"), User(2, "File用户2")]

# 客户端代码(业务逻辑)
if __name__ == "__main__":
    # 使用MySQL DAO
    mysql_dao = MySQLUserDAO()
    user1 = mysql_dao.find_by_id(1)
    print(user1)  # 输出:User(id=1, name=MySQL用户1)
    
    # 使用File DAO
    file_dao = FileUserDAO()
    users = file_dao.find_all()
    for user in users:
        print(user)  # 输出:File用户1、File用户2
    
    # 切换数据源仅需修改DAO实例,业务逻辑无需修改
应用场景
  • 需要访问多种数据源(如 MySQL、Redis、文件)的应用;
  • 需要分离数据访问逻辑与业务逻辑的应用;
  • 需要提高数据访问层的可扩展性的应用。

5.3 前端控制器模式(Front Controller Pattern)

核心思想:提供一个统一的入口来处理所有请求,集中管理请求的路由、认证、日志等通用逻辑,避免重复代码。
实现步骤
  1. 定义前端控制器:如FrontController,处理所有请求;
  2. 定义视图解析器:如ViewResolver,根据视图名称解析为实际的视图;
  3. 定义命令控制器:如CommandController,处理具体的业务请求;
  4. 客户端请求发送到前端控制器,前端控制器路由到对应的命令控制器,返回结果。
Python 代码示例
# 1. 视图解析器:将视图名称解析为HTML
class ViewResolver:
    def resolve(self, view_name: str) -> str:
        # 模拟视图解析
        if view_name == "home":
            return "<h1>首页</h1>"
        elif view_name == "user":
            return "<h1>用户页</h1>"
        return "<h1>404 页面不存在</h1>"

# 2. 命令控制器:处理具体请求
class HomeController:
    def handle(self) -> str:
        return "home"  # 返回视图名称

class UserController:
    def handle(self) -> str:
        return "user"  # 返回视图名称

# 3. 前端控制器:统一处理所有请求
class FrontController:
    def __init__(self):
        self._view_resolver = ViewResolver()
        # 路由映射:请求路径 → 命令控制器
        self._route_map = {
            "/": HomeController(),
            "/user": UserController()
        }
    
    # 处理请求
    def handle_request(self, path: str) -> str:
        # 1. 日志记录(通用逻辑)
        print(f"请求路径:{path}")
        
        # 2. 认证检查(通用逻辑)
        # ...
        
        # 3. 路由到命令控制器
        if path in self._route_map:
            controller = self._route_map[path]
            view_name = controller.handle()
            # 4. 解析视图
            return self._view_resolver.resolve(view_name)
        return "<h1>404 路径不存在</h1>"

# 客户端代码
if __name__ == "__main__":
    front_controller = FrontController()
    
    # 模拟请求首页
    html = front_controller.handle_request("/")
    print(html)  # 输出:<h1>首页</h1>
    
    # 模拟请求用户页
    html = front_controller.handle_request("/user")
    print(html)  # 输出:<h1>用户页</h1>
    
    # 模拟请求不存在的路径
    html = front_controller.handle_request("/nonexistent")
    print(html)  # 输出:<h1>404 路径不存在</h1>
应用场景
  • Web 应用的统一请求入口;
  • 需要集中管理通用请求逻辑(如认证、日志、路由)的应用;
  • 需要减少重复代码的应用。

六、设计模式的使用原则:SOLID

设计模式的使用需要遵循SOLID 原则,这是软件工程的 5 个核心设计原则,确保代码的可维护性和可扩展性:

  1. 单一职责原则(Single Responsibility Principle):一个类只负责一个功能,避免 “多功能类” 导致的代码复杂;
  2. 开闭原则(Open/Closed Principle):对扩展开放,对修改关闭 —— 新增功能通过扩展类实现,无需修改原有代码;
  3. 里氏替换原则(Liskov Substitution Principle):子类可以替换父类,且不会影响系统的正确性;
  4. 接口隔离原则(Interface Segregation Principle):使用小的、专门的接口,避免 “大而全” 的接口导致的依赖冗余;
  5. 依赖倒置原则(Dependency Inversion Principle):依赖抽象,而不是具体实现 —— 客户端依赖抽象接口,不直接依赖具体类。

七、如何选择合适的设计模式

  1. 分析问题类型

    • 若问题与对象创建有关,选择创建型模式(如单例、工厂、建造者);
    • 若问题与类或对象组合有关,选择结构型模式(如适配器、装饰器、外观);
    • 若问题与对象间通信有关,选择行为型模式(如观察者、策略、责任链);
    • 若问题与企业级架构有关,选择 J2EE 模式(如 MVC、DAO、前端控制器)。
  2. 遵循 SOLID 原则:确保所选模式符合代码的可维护性和可扩展性要求。

  3. 考虑场景复杂度:避免过度设计 —— 若问题简单,直接使用简单代码即可,无需强制使用设计模式。


总结

23 种经典设计模式(创建型 5 种、结构型 7 种、行为型 11 种)是软件工程的最佳实践,它们解决了 “重复出现的软件设计问题”,让代码更易读、易维护、易扩展。J2EE 设计模式则是针对企业级开发场景的补充,解决了分层架构、数据访问、请求处理等问题。

作为零基础开发者,学习设计模式的关键是理解核心思想,而非死记硬背代码 —— 从现实类比入手,思考模式解决的问题,再结合代码示例加深理解。随着开发经验的积累,你会逐渐掌握设计模式的使用场景,并能灵活应用于实际项目。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值