设计模式(python)

文章目录

  • [1. 概述](#1. 概述)
    • [1.1. 设计模式简介](#1.1. 设计模式简介)
    • [1.2. 设计模式的类型](#1.2. 设计模式的类型)
    • [1.3. 设计模式的优点](#1.3. 设计模式的优点)
    • [1.4. 设计模式的七大原则](#1.4. 设计模式的七大原则)
  • [2. 创建型模式(Creational Patterns)(共5种)](#2. 创建型模式(Creational Patterns)(共5种))
    • [2.1. 工厂模式(Factory,含两种)](#2.1. 工厂模式(Factory,含两种))
      • [2.1.1. 工厂模式的类型](#2.1.1. 工厂模式的类型)
      • [2.1.2. 简单工厂模式(Simple Factory)](#2.1.2. 简单工厂模式(Simple Factory))
      • [2.1.3. 工厂方法模式(Factory Method)](#2.1.3. 工厂方法模式(Factory Method))
      • [2.1.4. 抽象工厂模式(AbstractFactory)](#2.1.4. 抽象工厂模式(AbstractFactory))
    • [2.2. 单例模式(Singleton)](#2.2. 单例模式(Singleton))
    • [2.3. 建造者模式(Builder)](#2.3. 建造者模式(Builder))
    • [2.4. 原型模式(Prototype)](#2.4. 原型模式(Prototype))
  • [3. 结构型模式(Structural Patterns)(共7种)](#3. 结构型模式(Structural Patterns)(共7种))
    • [3.1. 适配器模式(Adapter)](#3.1. 适配器模式(Adapter))
    • [3.2. 桥接模式(Bridge)](#3.2. 桥接模式(Bridge))
    • [3.3. 组合模式(Composite)](#3.3. 组合模式(Composite))
    • [3.4. 装饰模式(Decorator)](#3.4. 装饰模式(Decorator))
    • [3.5. 外观模式(Facade)](#3.5. 外观模式(Facade))
    • [3.6. 享元模式(Flyweight)](#3.6. 享元模式(Flyweight))
    • [3.7. 代理模式(Proxy)](#3.7. 代理模式(Proxy))
  • [4. 行为型模式(Behavioral Patterns)(共11种)](#4. 行为型模式(Behavioral Patterns)(共11种))
    • [4.1. 职任链模式(Chain of Responsibility)](#4.1. 职任链模式(Chain of Responsibility))
    • [4.2. 命令模式(Command)](#4.2. 命令模式(Command))
    • [4.3. 解释器模式(Interpreter)](#4.3. 解释器模式(Interpreter))
    • [4.4. 迭代器模式(Iterator)](#4.4. 迭代器模式(Iterator))
    • [4.5. 中介者模式(Mediator)](#4.5. 中介者模式(Mediator))
    • [4.6. 备忘录模式(Memento)](#4.6. 备忘录模式(Memento))
    • [4.7. 观察者模式(Observer)](#4.7. 观察者模式(Observer))
    • [4.8. 状态模式(State)](#4.8. 状态模式(State))
    • [4.9. 策略模式(Strategy)](#4.9. 策略模式(Strategy))
    • [4.10. 模板方法模式(TemplateMethod)](#4.10. 模板方法模式(TemplateMethod))
    • [4.11. 访问者模式(Visitor)](#4.11. 访问者模式(Visitor))

参考:
https://www.runoob.com/design-pattern/design-pattern-intro.html
https://cloud.tencent.com/developer/news/1072964
https://cloud.tencent.com/developer/news/259520

1. 概述

1.1. 设计模式简介

设计模式(Design pattern)代表了最佳的实践,通常被有经验的面向对象的软件开发人员所采用。设计模式是软件开发人员在软件开发过程中面临的一般问题的解决方案。这些解决方案是众多软件开发人员经过相当长的一段时间的试验和错误总结出来的。

设计模式是一套被反复使用的、多数人知晓的、经过分类编目的、代码设计经验的总结。使用设计模式是为了重用代码、让代码更容易被他人理解、保证代码可靠性。 毫无疑问,设计模式于己于他人于系统都是多赢的,设计模式使代码编制真正工程化,设计模式是软件工程的基石,如同大厦的一块块砖石一样。项目中合理地运用设计模式可以完美地解决很多问题,每种模式在现实中都有相应的原理来与之对应,每种模式都描述了一个在我们周围不断重复发生的问题,以及该问题的核心解决方案,这也是设计模式能被广泛应用的原因。

什么是 GOF(全拼 Gang of Four)?

在 1994 年,由 Erich Gamma、Richard Helm、Ralph Johnson 和 John Vlissides 四人合著出版了一本名为 Design Patterns - Elements of Reusable Object-Oriented Software(中文译名:设计模式 - 可复用的面向对象软件元素) 的书,该书首次提到了软件开发中设计模式的概念。
四位作者合称 GOF(全拼 Gang of Four)

他们所提出的设计模式主要是基于以下的面向对象设计原则。
对接口编程而不是对实现编程。
优先使用对象组合而不是继承。

1.2. 设计模式的类型

根据设计模式的参考书 Design Patterns - Elements of Reusable Object-Oriented Software(中文译名:设计模式 - 可复用的面向对象软件元素) 中所提到的,总共有 23 种设计模式。这些模式可以分为三大类:创建型模式(Creational Patterns)、结构型模式(Structural Patterns)、行为型模式(Behavioral Patterns)。当然,我们还会讨论另一类设计模式:J2EE 设计模式。

序号 模式 描述 包括
1 创建型模式 这些设计模式提供了一种在创建对象的同时隐藏创建逻辑的方式, 而不是使用 new 运算符直接实例化对象。 这使得程序在判断针对某个给定实例需要创建哪些对象时更加灵活。 工厂模式(Factory Pattern) 抽象工厂模式(Abstract Factory Pattern) 单例模式(Singleton Pattern) 建造者模式(Builder Pattern) 原型模式(Prototype Pattern)
2 结构型模式 这些模式关注对象之间的组合和关系, 旨在解决如何构建灵活且可复用的类和对象结构。 适配器模式(Adapter Pattern) 桥接模式(Bridge Pattern) 过滤器模式(Filter、Criteria Pattern) 组合模式(Composite Pattern) 装饰器模式(Decorator Pattern) 外观模式(Facade Pattern) 享元模式(Flyweight Pattern) 代理模式(Proxy Pattern)
3 行为型模式 这些模式关注对象之间的通信和交互, 旨在解决对象之间的责任分配和算法的封装。 责任链模式(Chain of Responsibility Pattern) 命令模式(Command Pattern) 解释器模式(Interpreter Pattern) 迭代器模式(Iterator Pattern) 中介者模式(Mediator Pattern) 备忘录模式(Memento Pattern) 观察者模式(Observer Pattern) 状态模式(State Pattern) 空对象模式(Null Object Pattern) 策略模式(Strategy Pattern) 模板模式(Template Pattern) 访问者模式(Visitor Pattern)
4 J2EE 模式 这些设计模式特别关注表示层。这些模式是由 Sun Java Center 鉴定的。 MVC 模式(MVC Pattern) 业务代表模式(Business Delegate Pattern) 组合实体模式(Composite Entity Pattern) 数据访问对象模式(Data Access Object Pattern) 前端控制器模式(Front Controller Pattern) 拦截过滤器模式(Intercepting Filter Pattern) 服务定位器模式(Service Locator Pattern) 传输对象模式(Transfer Object Pattern)

1.3. 设计模式的优点

  • 提供了一种共享的设计词汇和概念,使开发人员能够更好地沟通和理解彼此的设计意图。
  • 提供了经过验证的解决方案,可以提高软件的可维护性、可复用性和灵活性。
  • 促进了代码的重用,避免了重复的设计和实现。
  • 通过遵循设计模式,可以减少系统中的错误和问题,提高代码质量。

1.4. 设计模式的七大原则

设计模式的七种原则通常被称为"SOLID原则",是面向对象设计中的基本原则,能够帮助开发人员编写出更加灵活、可扩展、可维护的代码。这七个原则分别是:
单一职责原则(Single Responsibility Principle,SRP): 一个类只负责一个职责或一个功能。这个原则强调的是高内聚、低耦合,可以降低类的复杂度,提高代码的可读性、可维护性和可重用性。
开闭原则(Open-Closed Principle,OCP): 一个类的行为应该是可扩展的,但是不可修改。这个原则强调的是代码的可维护性和可扩展性,通过抽象化来避免修改已有代码的风险,从而降低软件维护的成本。
里氏替换原则(Liskov Substitution Principle,LSP): 子类应该可以替换其父类并且不会影响程序的正确性。这个原则强调的是面向对象的继承和多态特性,通过保证子类的行为和父类一致,从而提高代码的可维护性和可扩展性。里氏替换原则是对开闭原则的补充。实现开闭原则的关键步骤就是抽象化,而基类与子类的继承关系就是抽象化的具体实现,所以里氏替换原则是对实现抽象化的具体步骤的规范。
接口隔离原则(Interface Segregation Principle,ISP): 一个类不应该依赖它不需要的接口,即一个类对其它类的依赖应该建立在最小的接口上。这个原则强调的是接口设计的合理性,避免不必要的接口导致类之间的耦合性过高,从而提高代码的灵活性和可维护性。
依赖倒置原则(Dependency Inversion Principle,DIP): 依赖于抽象而不是依赖于具体实现。这个原则强调的是代码的可扩展性和可维护性,通过抽象化来减少组件之间的耦合性,从而使得代码更加灵活、易于维护和扩展。这个原则是开闭原则的基础,具体内容:针对接口编程,依赖于抽象而不依赖于具体。
迪米特法则(Law of Demeter,LoD): 也叫最少知识原则(Least Knowledge Principle,LKP) ,一个对象应当对其他对象有尽可能少的了解,不需要了解的内容尽量不要去了解。这个原则强调的是组件之间的松耦合,通过减少组件之间的依赖关系,提高代码的可维护性和可重用性。
组合/聚合复用原则(Composite/Aggregate Reuse Principle,CARP): 尽量使用组合或聚合关系,而不是继承关系来达到代码复用的目的。这个原则强调的是通过组合和聚合的方式来实现代码复用,避免继承带来的一些问题,如父类和子类之间的强耦合性,从而提高代码的灵活性和可维护性。

2. 创建型模式(Creational Patterns)(共5种)

2.1. 工厂模式(Factory,含两种)

工厂模式(Factory Pattern)是最常用的设计模式之一,它提供了一种创建对象的方式 ,使得创建对象的过程与使用对象的过程分离 ,无需指定要创建的具体类(但是需要指定具体类的类型)。

通过使用工厂模式,可以将对象的创建逻辑封装在一个工厂类中,而不是在客户端代码中直接实例化对象,这样可以提高代码的可维护性和可扩展性。

2.1.1. 工厂模式的类型

  • 简单工厂模式(Simple Factory Pattern):
    简单工厂模式不是一个正式的设计模式,但它是工厂模式的基础。它使用一个单独的工厂类来创建不同的对象,根据传入的参数决定创建哪种类型的对象。
  • 工厂方法模式(Factory Method Pattern):
    工厂方法模式定义了一个创建对象的接口,但由子类决定实例化哪个类。工厂方法将对象的创建延迟到子类。
  • 抽象工厂模式(Abstract Factory Pattern):
    抽象工厂模式提供一个创建一系列相关或互相依赖对象的接口,而无需指定它们具体的类。

三种模式的核心区别:工厂职责范围

模式 工厂数量 产品数量 核心思想 使用场景 代码复杂度
简单工厂 1个工厂 多个产品 一个类搞定所有创建 产品类型不多,很少扩展 ⭐ 简单
工厂方法 N个工厂 N个产品 每个工厂只造一种产品 需要频繁添加新产品类型 ⭐⭐ 中等
抽象工厂 N个工厂 N个产品族 每个工厂造一系列相关产品 产品之间有相关性(如UI组件族) ⭐⭐⭐ 复杂
bash 复制代码
 简单工厂: 				工厂方法: 				抽象工厂:
 ┌─────────┐ 			┌──────────┐ 			┌──────────────┐
 │ Factory │ 			│ FactoryA │→ 产品A		│ FactoryA     │
 │         │ 			├──────────┤            │   ├── 产品A1 │
 │ create()│→ 产品A/B/C │ FactoryB │→ 产品B		│   └── 产品A2 │
 └─────────┘ 			├──────────┤            ├──────────────┤
 IF/ELSE判断 			│ FactoryC │→ 产品C 	│ FactoryB     │
 						└──────────┘            │   ├── 产品B1 │
                                                │   └── 产品B2 │
                                                └──────────────┘

感觉抽象工厂就是 复杂化的 简单工厂。

2.1.2. 简单工厂模式(Simple Factory)

  • 概要

简单工厂模式属于创建型模式,又叫做静态工厂方法(Static Factory Method)。简单工厂模式是由一个工厂对象决定创建哪一种产品类实例 ,可以根据参数的不同返回不同的产品实例,被创建的产品实例通常都具有共同的父类。

简单工厂模式是工厂模式家族中最简单实用的模式,可以理解为不同工厂模式的一个特殊实现。该模式并不属于GOF设计模式之一,但是它是抽象工厂模式,工厂方法模式的基础,并且有广泛得应用。

简单工厂模式通常被用于创建具有相似特征的对象,例如不同类型的图形对象、不同类型的数据库连接对象等。

实现逻辑:

在简单工厂模式中,有一个工厂类负责创建多个不同类型的产品对象。该工厂类通常包含一个公共的静态方法,该方法接受一个参数,用于指示要创建的对象类型,然后根据该参数创建相应的对象并返回给客户端。简言之:使用 if else 返回产品实例

优点:

简单工厂模式可以隐藏对象创建的复杂性,并使客户端代码更加简洁和易于维护。
缺点:

如果需要添加新的对象类型,则必须修改工厂类的代码。

同时,该模式也破坏了单一职责原则,因为工厂类不仅负责对象的创建,还负责了判断要创建哪个对象。

  • 实现

首先创建一个抽象接口 Shape 和实现了 Shape 接口的实体类Circle、Square、Rectangle。

下一步是定义工厂类 ShapeFactory(普通类),核心方法是 getShape(),接收参数CIRCLE / RECTANGLE / SQUARE。

FactoryPatternDemo 类使用 ShapeFactory.getShape() 来获取 Shape 对象。

python 复制代码
from abc import ABC, abstractmethod


# ============ 产品层 ============

class Shape(ABC):
    """形状接口"""
    
    @abstractmethod
    def draw(self) -> None:
        """绘制形状"""
        pass


class Circle(Shape):
    """圆形类"""
    
    def draw(self) -> None:
        print("绘制圆形")


class Rectangle(Shape):
    """矩形类"""
    
    def draw(self) -> None:
        print("绘制矩形")


class Square(Shape):
    """正方形类"""
    
    def draw(self) -> None:
        print("绘制正方形")


# ============ 简单工厂 ============

class ShapeFactory:
    """形状工厂类"""
    
    @staticmethod
    def get_shape(shape_type: str) -> 'Shape':
        """
        获取形状对象
        
        Args:
            shape_type: 形状类型 (CIRCLE / RECTANGLE / SQUARE)
            
        Returns:
            Shape: 对应类型的形状实例
            
        Raises:
            ValueError: 当传入未知形状类型时
        """
        if shape_type is None:
            return None
        
        shape_type = shape_type.upper()
        
        if shape_type == "CIRCLE":
            return Circle()
        elif shape_type == "RECTANGLE":
            return Rectangle()
        elif shape_type == "SQUARE":
            return Square()
        else:
            raise ValueError(f"未知的形状类型: {shape_type}")


# ============ 客户端代码 ============

class FactoryPatternDemo:
    """工厂模式演示类"""
    
    @staticmethod
    def main():
        """主方法 - 演示工厂模式的使用"""
        print("=== 工厂模式演示 ===\n")
        
        # 获取圆形对象,并调用它的 draw 方法
        print("1. 获取圆形对象并绘制:")
        shape1 = ShapeFactory.get_shape("CIRCLE")
        shape1.draw()
        print()
        
        # 获取矩形对象,并调用它的 draw 方法
        print("2. 获取矩形对象并绘制:")
        shape2 = ShapeFactory.get_shape("RECTANGLE")
        shape2.draw()
        print()
        
        # 获取正方形对象,并调用它的 draw 方法
        print("3. 获取正方形对象并绘制:")
        shape3 = ShapeFactory.get_shape("SQUARE")
        shape3.draw()
        print()
        
        # 测试小写输入
        print("4. 测试小写输入 (circle):")
        shape4 = ShapeFactory.get_shape("circle")
        shape4.draw()
        print()
        
        # 测试错误处理
        print("5. 测试无效输入 (TRIANGLE):")
        try:
            invalid_shape = ShapeFactory.get_shape("TRIANGLE")
        except ValueError as e:
            print(f"   错误: {e}")


if __name__ == "__main__":
    FactoryPatternDemo.main()

运行结果:

bash 复制代码
> python.exe .\simple_factory_pattern.py
=== 工厂模式演示 ===

1. 获取圆形对象并绘制:
绘制圆形

2. 获取矩形对象并绘制:
绘制矩形

3. 获取正方形对象并绘制:
绘制正方形

4. 测试小写输入 (circle):
绘制圆形

5. 测试无效输入 (TRIANGLE):
   错误: 未知的形状类型: TRIANGL

2.1.3. 工厂方法模式(Factory Method)

  • 概要

工厂方法模式是一种创建型设计模式,它提供了一种将产品对象的创建过程委托给工厂子类的方式。

该模式常用于框架和库中,因为它可以使用户扩展框架或库的功能,而无需更改框架或库的源代码。

优点:

可以使代码更加灵活,因为在运行时可以选择要实例化的产品对象类型。例如,可以轻松地添加新的子类来创建不同的对象类型,而无需更改现有的代码。

该模式还提供了一种解耦的方式,因为它将产品对象的创建逻辑与其使用代码分离。这可以使代码更加可维护和可测试,因为可以独立地测试和修改对象的创建逻辑和使用代码。

  • 实现

首先、定义抽象接口 AbstractProduct,派生出两个具体产品类 ConcreteProductA、ConcreteProductB。

创建一个工厂抽象基类 AbstractFactory,包含一个抽象工厂方法 create_product,该方法在子类中的派生方法,创建具体的产品对象,并返回该产品对象。包含一个操作工厂方法 operation_product,该方法操作工厂子类的具体操作内容。

创建两个具体的工厂子类 ConcreteFactoryA、ConcreteFactoryB,实现抽象工厂方法 create_product 来创建具体的产品对象。

python 复制代码
from abc import ABC, abstractmethod


# ============ 产品层 ============

class AbstractProduct(ABC):
    """抽象产品类"""
    
    @abstractmethod
    def use(self) -> None:
        """使用产品的方法,由具体产品类实现"""
        pass


class ConcreteProductA(AbstractProduct):
    """具体产品类 A"""
    
    def use(self) -> None:
        print("使用具体产品 A")


class ConcreteProductB(AbstractProduct):
    """具体产品类 B"""
    
    def use(self) -> None:
        print("使用具体产品 B")


# ============ 工厂层 ============

class AbstractFactory(ABC):
    """抽象工厂类"""
    
    @abstractmethod
    def create_product(self) -> AbstractProduct:
        """
        工厂方法
        
        注意:工厂方法的返回类型必须是 Product 类型
        具体工厂类将实现此方法,返回具体的产品实例
        """
        pass
    
    def operation_product(self) -> None:
        """
        业务逻辑方法
        
        调用工厂方法创建产品,然后使用产品
        """
        # 调用工厂方法创建一个 Product 对象
        product = self.create_product()
        
        # 使用创建的产品
        print(f"工厂: 我使用的是 {product.__class__.__name__}")
        product.use()


class ConcreteFactoryA(AbstractFactory):
    """具体工厂类 A"""
    
    def create_product(self) -> AbstractProduct:
        """实现工厂方法,返回 ConcreteProductA 实例"""
        return ConcreteProductA()


class ConcreteFactoryB(AbstractFactory):
    """具体工厂类 B"""
    
    def create_product(self) -> AbstractProduct:
        """实现工厂方法,返回 ConcreteProductB 实例"""
        return ConcreteProductB()


# ============ 客户端代码 ============

class FactoryMethodPatternDemo:
    """工厂方法模式演示类"""
    
    @staticmethod
    def main():
        """主方法 - 演示工厂方法模式的使用"""
        print("=== 工厂方法模式演示 ===\n")
        
        print("客户端: 我不关心工厂类,它们都一样工作。")
        print("只要它们继承自 Factory 基类,我就能使用它们。\n")
        
        # 使用 ConcreteFactoryA
        print("使用 ConcreteFactoryA:")
        factory_a = ConcreteFactoryA()
        factory_a.operation_product()
        
        print()
        
        # 使用 ConcreteFactoryB
        print("使用 ConcreteFactoryB:")
        factory_b = ConcreteFactoryB()
        factory_b.operation_product()


if __name__ == "__main__":
    FactoryMethodPatternDemo.main()

运行结果:

bash 复制代码
> python.exe .\factory_method_pattern.py
=== 工厂方法模式演示 ===

客户端: 我不关心工厂类,它们都一样工作。
只要它们继承自 Factory 基类,我就能使用它们。

使用 ConcreteFactoryA:
工厂: 我使用的是 ConcreteProductA
使用具体产品 A

使用 ConcreteFactoryB:
工厂: 我使用的是 ConcreteProductB
使用具体产品 B

2.1.4. 抽象工厂模式(AbstractFactory)

  • 概要

抽象工厂模式是围绕一个超级工厂创建其他工厂。该超级工厂又称为其他工厂的工厂。该模式属于创建型模式,它提供了一种创建对象的最佳方式。

实现逻辑:

在抽象工厂模式中,对外接口负责创建一个相关对象的具体工厂,不需要显式指定具体的工厂类。每个具体工厂都能按照工厂模式提供产品对象。

通过使用抽象工厂模式,可以将客户端与具体产品的创建过程解耦,使得客户端可以通过工厂接口来创建一族产品。

该模式通常涉及一族相关的产品,每个具体工厂类负责创建该族中的具体产品。客户端通过使用抽象工厂接口来创建产品对象,而不需要直接使用具体产品的实现类。

优点 :

确保同一产品族的对象一起工作。

客户端不需要知道每个对象的具体类,简化了代码。
缺点:

扩展产品族非常困难。增加一个新的产品族需要修改抽象工厂和所有具体工厂的代码。(需要在原有的抽象工厂中增加新接口,同时需要在原有具体工厂中增加新接口且返回None)

角色:
抽象工厂(Abstract Factory): 声明了一组用于创建产品对象的方法,每个方法对应一种产品类型。抽象工厂可以是接口或抽象类。
具体工厂(Concrete Factory): 实现了抽象工厂接口,负责创建具体产品对象的实例。
抽象产品(Abstract Product): 定义了一组产品对象的共同接口或抽象类,描述了产品对象的公共方法。
具体产品(Concrete Product): 实现了抽象产品接口,定义了具体产品的特定行为和属性。

  • 实现

首先创建两个抽象类 Shape 和 Color;并实现具体接口的实体类。

下一步创建抽象工厂类 AbstractFactory,并实现其派生类 ShapeFactory 和 ColorFactory。

然后创建一个工厂创造器/生成器类 FactoryProducer。

AbstractFactoryPatternDemo 类使用 FactoryProducer.getFactory(),通过传递 Shape/Color,来获取 AbstractFactory 对象(实际返回具体的工厂类)。

向 AbstractFactory.getShape 传递形状信息 CIRCLE/RECTANGLE/SQUARE(属于 Shape),以便获取具体 Shape 对象。同时向 AbstractFactory.getColor() 传递颜色信息 RED/GREEN/BLUE(属于 Color),以便获取具体 Color 对象。

python 复制代码
from abc import ABC, abstractmethod
from typing import Optional, TYPE_CHECKING

# ============ 模型层 (models) ============
# ---- Shape 接口及实现 ----
class Shape(ABC):
    """形状接口"""
    @abstractmethod
    def draw(self) -> None:
        pass

class Circle(Shape):
    """圆形"""
    def draw(self) -> None:
        print("绘制圆形")

class Rectangle(Shape):
    """矩形"""
    def draw(self) -> None:
        print("绘制矩形")

class Square(Shape):
    """正方形"""
    def draw(self) -> None:
        print("绘制正方形")

# ---- Color 接口及实现 ----
class Color(ABC):
    """颜色接口"""
    @abstractmethod
    def fill(self) -> None:
        pass

class Red(Color):
    """红色"""
    def fill(self) -> None:
        print("填充红色")

class Green(Color):
    """绿色"""
    def fill(self) -> None:
        print("填充绿色")

class Blue(Color):
    """蓝色"""
    def fill(self) -> None:
        print("填充蓝色")

# ============ 工厂层 (factories) ============
# ---- 抽象工厂 ----
class AbstractFactory(ABC):
    """抽象工厂类"""
    @abstractmethod
    def get_shape(self, shape_type: str) -> Optional[Shape]:
        pass
    
    @abstractmethod
    def get_color(self, color_type: str) -> Optional[Color]:
        pass

# ---- 形状工厂 ----
class ShapeFactory(AbstractFactory):
    """形状工厂"""
    def get_shape(self, shape_type: str) -> Optional[Shape]:
        if shape_type is None:
            return None
        shape_type = shape_type.upper()
        
        if shape_type == "CIRCLE":
            return Circle()
        elif shape_type == "RECTANGLE":
            return Rectangle()
        elif shape_type == "SQUARE":
            return Square()
        else:
            return None
    
    def get_color(self, color_type: str) -> Optional[Color]:
        """形状工厂不提供颜色产品"""
        return None

# ---- 颜色工厂 ----
class ColorFactory(AbstractFactory):
    """颜色工厂"""
    def get_shape(self, shape_type: str) -> Optional[Shape]:
        """颜色工厂不提供形状产品"""
        return None
    
    def get_color(self, color_type: str) -> Optional[Color]:
        if color_type is None:
            return None
        color_type = color_type.upper()
        
        if color_type == "RED":
            return Red()
        elif color_type == "GREEN":
            return Green()
        elif color_type == "BLUE":
            return Blue()
        else:
            return None

# ---- 工厂生成器 ----
class FactoryProducer:
    """工厂生成器类"""
    @staticmethod
    def get_factory(factory_type: str) -> Optional[AbstractFactory]:
        """
        获取对应的工厂对象
        
        Args:
            factory_type: 工厂类型 (SHAPE / COLOR)
            
        Returns:
            AbstractFactory: 对应的工厂实例
        """
        if factory_type is None:
            return None
        factory_type = factory_type.upper()
        
        if factory_type == "SHAPE":
            return ShapeFactory()
        elif factory_type == "COLOR":
            return ColorFactory()
        else:
            return None

# ============ 演示层 ============
class AbstractFactoryPatternDemo:
    """抽象工厂模式演示类"""
    @staticmethod
    def main():
        """主方法 - 演示抽象工厂模式的使用"""
        print("=== 抽象工厂模式演示 ===\n")
        
        # 获取形状工厂
        print("1. 获取形状工厂并创建形状:")
        shape_factory = FactoryProducer.get_factory("SHAPE")
        
        # 获取 Circle 对象,并调用它的 draw 方法
        shape1 = shape_factory.get_shape("CIRCLE")
        shape1.draw()
        
        # 获取 Rectangle 对象,并调用它的 draw 方法
        shape2 = shape_factory.get_shape("RECTANGLE")
        shape2.draw()
        
        # 获取 Square 对象,并调用它的 draw 方法
        shape3 = shape_factory.get_shape("SQUARE")
        shape3.draw()
        
        print()
        
        # 获取颜色工厂
        print("2. 获取颜色工厂并创建颜色:")
        color_factory = FactoryProducer.get_factory("COLOR")
        
        # 获取 Red 对象,并调用它的 fill 方法
        color1 = color_factory.get_color("RED")
        color1.fill()
        
        # 获取 Green 对象,并调用它的 fill 方法
        color2 = color_factory.get_color("GREEN")
        color2.fill()
        
        # 获取 Blue 对象,并调用它的 fill 方法
        color3 = color_factory.get_color("BLUE")
        color3.fill()
        
        print()
        
        # 演示:形状工厂无法获取颜色
        print("3. 形状工厂尝试获取颜色 (返回 None):")
        null_color = shape_factory.get_color("RED")
        print(f"   结果: {null_color}")
        
        # 演示:颜色工厂无法获取形状
        print("4. 颜色工厂尝试获取形状 (返回 None):")
        null_shape = color_factory.get_shape("CIRCLE")
        print(f"   结果: {null_shape}")

if __name__ == "__main__":
    AbstractFactoryPatternDemo.main()

运行结果:

bash 复制代码
> python.exe .\abstract_factory_pattern.py
=== 抽象工厂模式演示 ===

1. 获取形状工厂并创建形状:
绘制圆形
绘制矩形
绘制正方形

2. 获取颜色工厂并创建颜色:
填充红色
填充绿色
填充蓝色

3. 形状工厂尝试获取颜色 (返回 None):
   结果: None
4. 颜色工厂尝试获取形状 (返回 None):
   结果: None

2.2. 单例模式(Singleton)

  • 单例模式的几种实现方式
  1. 懒汉式,线程不安全
  2. 懒汉式,线程安全
  3. 饿汉式
  4. 双检锁/双重校验锁(DCL,即 double-checked locking)
  5. 登记式/静态内部类
  6. 枚举

一般情况下,不建议使用第 1 种和第 2 种懒汉方式,建议使用第 3 种饿汉方式。只有在要明确实现 lazy loading 效果时,才会使用第 5 种登记方式。如果涉及到反序列化创建对象时,可以尝试使用第 6 种枚举方式。如果有其他特殊的需求,可以考虑使用第 4 种双检锁方式。

  • 概要

单例模式(Singleton)是一种创建型设计模式,其原理是确保一个类只有一个实例,并且提供了一个访问该实例的全局点。

通常,单例模式使用一个私有构造函数来确保只有一个对象被创建。然后,需要提供一个全局访问该对象的方法,使得任何代码都可以访问该对象,而不必担心创建多个实例。

实现步骤:

创建一个私有构造函数,以确保类不能从外部实例化。

创建一个私有静态变量,用于存储类的唯一实例。

创建一个公共静态方法,用于访问该实例。

在公共静态方法中,如果实例不存在,则创建一个新实例并将其分配给静态变量。否则,返回现有的实例。

优点:

单例模式可以有效地避免重复的内存分配,特别是当对象需要被频繁地创建和销毁时。另外,单例模式还提供了一种简单的方式来控制全局状态,因为只有一个实例存在,可以确保任何代码都在同一个对象上运行。
缺点:

单例模式可能导致线程安全问题。如果多个线程同时尝试访问单例实例,可能会导致竞争条件。因此,在实现单例模式时需要格外小心,并考虑到线程安全问题。

结构:

单例类:包含单例实例的类,通常将构造函数声明为私有。

静态成员变量:用于存储单例实例的静态成员变量。

获取实例方法:静态方法,用于获取单例实例。

私有构造函数:防止外部直接实例化单例类。

线程安全处理:确保在多线程环境下单例实例的创建是安全的。

  • 实现

首先创建一个 SingleObject 类。SingleObject 类有它的私有构造函数和本身的一个静态实例。

SingleObject 类提供了一个静态方法,供外界获取它的静态实例。SingletonPatternDemo 类使用 SingleObject 类来获取 SingleObject 对象。

python 复制代码
"""
单例模式 (Singleton Pattern) - SingleObject 实现

确保一个类只有一个实例,并提供一个全局访问点。
"""

class SingleObject:
    """
    SingleObject 单例类
    
    包含私有构造函数和静态实例,
    提供静态方法 get_instance() 供外界获取实例。
    """
    
    # 静态实例(类属性),用于存储唯一的实例
    __instance = None
    
    def __new__(cls):
        """
        私有构造函数
        
        控制实例的创建,确保只有一个实例存在。
        如果实例已存在,则返回现有实例。
        """
        if cls.__instance is None:
            cls.__instance = super(SingleObject, cls).__new__(cls)
        return cls.__instance
    
    @staticmethod
    def get_instance():
        """
        静态方法,供外界获取静态实例
        
        如果实例不存在,则创建新实例;
        如果实例已存在,则返回现有实例。
        
        Returns:
            SingleObject: 唯一的单例实例
        """
        if SingleObject.__instance is None:
            SingleObject.__instance = SingleObject()
        return SingleObject.__instance
    
    def __init__(self):
        """初始化方法"""
        if not hasattr(self, '_initialized'):
            self._initialized = True
            self.message = "我是唯一的 SingleObject 实例"
    
    def show_message(self):
        """显示消息"""
        print(f"SingleObject: {self.message}")


class SingletonPatternDemo:
    """单例模式演示类"""
    
    @staticmethod
    def main():
        """主方法 - 演示 SingleObject 的使用"""
        print("=== 单例模式演示 (SingleObject) ===\n")
        
        # 获取 SingleObject 实例
        print("1. 获取 SingleObject 实例:")
        object1 = SingleObject.get_instance()
        object1.show_message()
        print(f"   实例1 ID: {id(object1)}")
        
        # 再次获取实例,验证是否为同一实例
        print("\n2. 再次获取实例,验证单例:")
        object2 = SingleObject.get_instance()
        object2.show_message()
        print(f"   实例2 ID: {id(object2)}")
        print(f"   是否为同一实例: {object1 is object2}")
        
        # 验证状态共享
        print("\n3. 验证状态共享:")
        object1.message = "修改后的消息"
        print(f"   实例1 消息: {object1.message}")
        print(f"   实例2 消息: {object2.message}")
        
        # 尝试通过构造函数创建(实际上还是返回同一个实例)
        print("\n4. 尝试通过构造函数创建:")
        object3 = SingleObject()
        print(f"   实例3 ID: {id(object3)}")
        print(f"   是否为同一实例: {object1 is object3}")
        object3.show_message()


if __name__ == "__main__":
    SingletonPatternDemo.main()

运行结果:

bash 复制代码
> python.exe .\single_object.py                        
=== 单例模式演示 (SingleObject) ===

1. 获取 SingleObject 实例:
SingleObject: 我是唯一的 SingleObject 实例
   实例1 ID: 2023036910896

2. 再次获取实例,验证单例:
SingleObject: 我是唯一的 SingleObject 实例
   实例2 ID: 2023036910896
   是否为同一实例: True

3. 验证状态共享:
   实例1 消息: 修改后的消息
   实例2 消息: 修改后的消息

4. 尝试通过构造函数创建:
   实例3 ID: 2023036910896
   是否为同一实例: True
SingleObject: 修改后的消息

2.3. 建造者模式(Builder)

  • 概要

建造者模式是一种创建型设计模式,它允许创建复杂对象的步骤与表示方式相分离,从而可以创建具有不同表示形式的对象。

复制代码
构建过程(Construction):
	创建对象的步骤和流程
	比如制作套餐的流程:选汉堡 → 选饮料 → 组合成套餐
表示(Representation):
	最终构建出来的具体对象形态
	比如素食套餐、非素食套餐、豪华套餐

在 Python 中,建造者模式通常使用构造者类来封装对象的构造过程,以及指导客户端如何构建对象。

具体的构造者类可以继承自一个抽象的构造者类,并实现其定义的构造方法,从而实现具体的构造过程。

客户端可以选择任何一个具体构造者类来构建对象,并且也可以自定义构造者类来实现自定义的构造过程。

  • 实现

    假设一个快餐店的商业案例,
    一个典型的套餐可以是一个汉堡(Burger)和一杯冷饮(ColdDrink)。
    汉堡(Burger)可以是素食汉堡(Veg Burger)或鸡肉汉堡(Chicken Burger),它们是包在纸盒中。
    冷饮(ColdDrink)可以是可口可乐(coke)或百事可乐(pepsi),它们是装在瓶子中。

首先创建一个表示食物条目的 Item 虚拟接口,实现 Item 接口的实体类(Burger 和 ColdDrink);以及一个表示包装的 Packing 虚拟接口,实现 Packing 接口的实体类(Wrapper 和 Bottle);汉堡是包在纸盒中,冷饮是装在瓶子中。

然后创建一个 Meal 实体类表示一餐,带有 Item 的 ArrayList;一个结合不同类型 Meal 对象的 MealBuilder 实体类。BuilderPatternDemo 类使用 MealBuilder 来创建一个 Meal。

python 复制代码
"""
建造者模式 (Builder Pattern)

快餐店商业案例:
- 套餐包含汉堡和冷饮
- 汉堡:素食汉堡、鸡肉汉堡(纸盒包装)
- 冷饮:可口可乐、百事可乐(瓶子包装)
"""

from abc import ABC, abstractmethod
from typing import List


# ============ 包装接口及实现 ============

class Packing(ABC):
    """包装接口"""
    
    @abstractmethod
    def pack(self) -> str:
        """返回包装方式"""
        pass


class Wrapper(Packing):
    """纸盒包装"""
    
    def pack(self) -> str:
        return "纸盒"


class Bottle(Packing):
    """瓶子包装"""
    
    def pack(self) -> str:
        return "瓶子"


# ============ 食物条目接口及实现 ============

class Item(ABC):
    """食物条目接口"""
    
    @abstractmethod
    def name(self) -> str:
        """返回食物名称"""
        pass
    
    @abstractmethod
    def packing(self) -> Packing:
        """返回包装方式"""
        pass
    
    @abstractmethod
    def price(self) -> float:
        """返回价格"""
        pass


class Burger(Item, ABC):
    """汉堡抽象类"""
    
    def packing(self) -> Packing:
        return Wrapper()


class ColdDrink(Item, ABC):
    """冷饮抽象类"""
    
    def packing(self) -> Packing:
        return Bottle()


class VegBurger(Burger):
    """素食汉堡"""
    
    def name(self) -> str:
        return "素食汉堡"
    
    def price(self) -> float:
        return 25.0


class ChickenBurger(Burger):
    """鸡肉汉堡"""
    
    def name(self) -> str:
        return "鸡肉汉堡"
    
    def price(self) -> float:
        return 35.0


class Coke(ColdDrink):
    """可口可乐"""
    
    def name(self) -> str:
        return "可口可乐"
    
    def price(self) -> float:
        return 10.0


class Pepsi(ColdDrink):
    """百事可乐"""
    
    def name(self) -> str:
        return "百事可乐"
    
    def price(self) -> float:
        return 10.0


# ============ 套餐类 ============

class Meal:
    """套餐类"""
    
    def __init__(self):
        self.items: List[Item] = []
    
    def add_item(self, item: Item) -> None:
        """添加食物条目"""
        self.items.append(item)
    
    def get_cost(self) -> float:
        """计算套餐总价"""
        total = 0.0
        for item in self.items:
            total += item.price()
        return total
    
    def show_items(self) -> None:
        """显示套餐内容"""
        print("套餐内容:")
        print("-" * 50)
        for item in self.items:
            print(f"  食物: {item.name()}")
            print(f"  包装: {item.packing().pack()}")
            print(f"  价格: {item.price()}元")
            print("-" * 50)
        print(f"总价: {self.get_cost()}元")


# ============ 建造者类 ============

class MealBuilder:
    """套餐建造者"""
    
    def prepare_veg_meal(self) -> Meal:
        """
        准备素食套餐
        
        Returns:
            Meal: 包含素食汉堡和可口可乐的套餐
        """
        meal = Meal()
        meal.add_item(VegBurger())
        meal.add_item(Coke())
        return meal
    
    def prepare_non_veg_meal(self) -> Meal:
        """
        准备非素食套餐
        
        Returns:
            Meal: 包含鸡肉汉堡和百事可乐的套餐
        """
        meal = Meal()
        meal.add_item(ChickenBurger())
        meal.add_item(Pepsi())
        return meal
    
    def prepare_combo_meal(self) -> Meal:
        """
        准备组合套餐
        
        Returns:
            Meal: 包含素食汉堡、鸡肉汉堡和可口可乐的套餐
        """
        meal = Meal()
        meal.add_item(VegBurger())
        meal.add_item(ChickenBurger())
        meal.add_item(Coke())
        return meal


# ============ 演示类 ============

class BuilderPatternDemo:
    """建造者模式演示类"""
    
    @staticmethod
    def main():
        """主方法 - 演示建造者模式的使用"""
        print("=" * 60)
        print("建造者模式演示 - 快餐店套餐系统")
        print("=" * 60)
        
        # 创建建造者
        meal_builder = MealBuilder()
        
        # 1. 素食套餐
        print("\n【1. 素食套餐】")
        print("=" * 60)
        veg_meal = meal_builder.prepare_veg_meal()
        veg_meal.show_items()
        
        # 2. 非素食套餐
        print("\n【2. 非素食套餐】")
        print("=" * 60)
        non_veg_meal = meal_builder.prepare_non_veg_meal()
        non_veg_meal.show_items()
        
        # 3. 组合套餐
        print("\n【3. 组合套餐(双人份)】")
        print("=" * 60)
        combo_meal = meal_builder.prepare_combo_meal()
        combo_meal.show_items()
        
        # 总结
        print("\n" + "=" * 60)
        print("建造者模式的优势:")
        print("=" * 60)
        print("1. 将复杂对象的构建与其表示分离")
        print("2. 同样的构建过程可以创建不同的表示")
        print("3. 客户端无需知道产品内部组成的细节")
        print("4. 更好的控制构建过程")
        print("=" * 60)


if __name__ == "__main__":
    BuilderPatternDemo.main()

运行结果:

bash 复制代码
> python.exe .\builder_pattern.py                      
============================================================
建造者模式演示 - 快餐店套餐系统
============================================================

【1. 素食套餐】
============================================================
套餐内容:
--------------------------------------------------
  食物: 素食汉堡
  包装: 纸盒
  价格: 25.0元
--------------------------------------------------
  食物: 可口可乐
  包装: 瓶子
  价格: 10.0元
--------------------------------------------------
总价: 35.0元

【2. 非素食套餐】
============================================================
套餐内容:
--------------------------------------------------
  食物: 鸡肉汉堡
  包装: 纸盒
  价格: 35.0元
--------------------------------------------------
  食物: 百事可乐
  包装: 瓶子
  价格: 10.0元
--------------------------------------------------
总价: 45.0元

【3. 组合套餐(双人份)】
============================================================
套餐内容:
--------------------------------------------------
  食物: 素食汉堡
  包装: 纸盒
  价格: 25.0元
--------------------------------------------------
  食物: 鸡肉汉堡
  包装: 纸盒
  价格: 35.0元
--------------------------------------------------
  食物: 可口可乐
  包装: 瓶子
  价格: 10.0元
--------------------------------------------------
总价: 70.0元

============================================================
建造者模式的优势:
============================================================
1. 将复杂对象的构建与其表示分离
2. 同样的构建过程可以创建不同的表示
3. 客户端无需知道产品内部组成的细节
4. 更好的控制构建过程
============================================================

2.4. 原型模式(Prototype)

  • 概要

原型模式是一种创建型设计模式,它允许通过复制(克隆)现有对象来创建新对象,而不是通过实例化类来创建对象,从而避免了重复的初始化操作。

在 Python 中,可以使用 copy 模块中的 copy() 和 deepcopy() 函数来实现原型模式。

copy() 函数执行的是浅复制 ,它复制对象本身,但不复制对象引用的内存空间,因此如果原型对象中包含可变对象(如列表、字典等),那么新对象和原型对象将共享这些可变对象。

deepcopy() 函数则执行深复制,它会递归地复制对象及其引用的所有对象,因此新对象和原型对象不会共享任何对象。

  • 实现

首先创建一个抽象类 Shape 和扩展了 Shape 类的实体类。

下一步是定义类 ShapeCache,该类批量创建所有的 Shape 对象,并将这些对象存储在一个 Hashtable 中,在请求的时候返回它们的克隆。

PrototypePatternDemo 类使用 ShapeCache 类来获取 Shape 对象。

python 复制代码
"""
原型模式 (Prototype Pattern)

通过复制现有对象来创建新对象,而不是从头创建。
"""

from abc import ABC, abstractmethod
from typing import Dict
import copy


# ============ 抽象原型类 ============

class Shape(ABC):
    """
    形状抽象类(原型基类)
    
    所有具体形状类都需要实现 clone 方法
    """
    
    def __init__(self):
        self.id: str = ""
        self.shape_type: str = ""
    
    @abstractmethod
    def draw(self) -> None:
        """绘制形状"""
        pass
    
    def clone(self):
        """
        克隆方法
        
        使用 Python 的 copy 模块进行深拷贝
        """
        return copy.deepcopy(self)
    
    def get_id(self) -> str:
        """获取形状ID"""
        return self.id
    
    def set_id(self, id: str) -> None:
        """设置形状ID"""
        self.id = id
    
    def get_type(self) -> str:
        """获取形状类型"""
        return self.shape_type


# ============ 具体原型类 ============

class Circle(Shape):
    """圆形类"""
    
    def __init__(self):
        super().__init__()
        self.shape_type = "圆形"
    
    def draw(self) -> None:
        print(f"绘制 {self.shape_type} [ID: {self.id}]")


class Rectangle(Shape):
    """矩形类"""
    
    def __init__(self):
        super().__init__()
        self.shape_type = "矩形"
    
    def draw(self) -> None:
        print(f"绘制 {self.shape_type} [ID: {self.id}]")


class Square(Shape):
    """正方形类"""
    
    def __init__(self):
        super().__init__()
        self.shape_type = "正方形"
    
    def draw(self) -> None:
        print(f"绘制 {self.shape_type} [ID: {self.id}]")


# ============ 原型缓存类 ============

class ShapeCache:
    """
    形状缓存类
    
    存储形状原型对象,并在请求时返回它们的克隆
    """
    
    def __init__(self):
        self.shape_map: Dict[str, Shape] = {}
    
    def load_cache(self) -> None:
        """
        加载缓存
        
        创建各种形状的原型并存储在 Hashtable(字典)中
        """
        # 创建圆形原型
        circle = Circle()
        circle.set_id("1")
        self.shape_map[circle.get_id()] = circle
        
        # 创建矩形原型
        rectangle = Rectangle()
        rectangle.set_id("2")
        self.shape_map[rectangle.get_id()] = rectangle
        
        # 创建正方形原型
        square = Square()
        square.set_id("3")
        self.shape_map[square.get_id()] = square
    
    def get_shape(self, shape_id: str) -> Shape:
        """
        获取形状的克隆
        
        Args:
            shape_id: 形状ID
            
        Returns:
            Shape: 形状对象的克隆
            
        Raises:
            KeyError: 当找不到对应ID的形状时
        """
        cached_shape = self.shape_map.get(shape_id)
        if cached_shape is None:
            raise KeyError(f"找不到ID为 {shape_id} 的形状")
        
        # 返回克隆对象
        return cached_shape.clone()


# ============ 演示类 ============

class PrototypePatternDemo:
    """原型模式演示类"""
    
    @staticmethod
    def main():
        """主方法 - 演示原型模式的使用"""
        print("=" * 60)
        print("原型模式演示")
        print("=" * 60)
        
        # 创建缓存并加载原型
        print("\n1. 创建形状缓存并加载原型:")
        print("-" * 40)
        shape_cache = ShapeCache()
        shape_cache.load_cache()
        print("缓存加载完成!")
        
        # 获取并克隆形状
        print("\n2. 从缓存获取克隆对象:")
        print("-" * 40)
        
        # 获取圆形克隆
        cloned_circle = shape_cache.get_shape("1")
        print(f"获取形状: {cloned_circle.get_type()}")
        print(f"形状ID: {cloned_circle.get_id()}")
        cloned_circle.draw()
        
        print()
        
        # 获取矩形克隆
        cloned_rectangle = shape_cache.get_shape("2")
        print(f"获取形状: {cloned_rectangle.get_type()}")
        print(f"形状ID: {cloned_rectangle.get_id()}")
        cloned_rectangle.draw()
        
        print()
        
        # 获取正方形克隆
        cloned_square = shape_cache.get_shape("3")
        print(f"获取形状: {cloned_square.get_type()}")
        print(f"形状ID: {cloned_square.get_id()}")
        cloned_square.draw()
        
        # 验证克隆是独立的对象
        print("\n3. 验证克隆对象是独立的:")
        print("-" * 40)
        circle_clone_1 = shape_cache.get_shape("1")
        circle_clone_2 = shape_cache.get_shape("1")
        
        print(f"克隆1 ID: {id(circle_clone_1)}")
        print(f"克隆2 ID: {id(circle_clone_2)}")
        print(f"是否为同一对象: {circle_clone_1 is circle_clone_2}")
        print(f"是否相等: {circle_clone_1.get_id() == circle_clone_2.get_id()}")
        
        # 修改克隆对象不影响其他克隆
        print("\n4. 修改克隆对象验证独立性:")
        print("-" * 40)
        circle_clone_1.set_id("1-修改")
        circle_clone_3 = shape_cache.get_shape("1")
        
        print(f"修改后的克隆1 ID: {circle_clone_1.get_id()}")
        print(f"新克隆3 ID: {circle_clone_3.get_id()}")
        print(f"原型未被修改: {circle_clone_3.get_id() == '1'}")
        
        # 总结
        print("\n" + "=" * 60)
        print("原型模式的优势:")
        print("=" * 60)
        print("1. 减少对象创建的开销(特别是创建成本高的对象)")
        print("2. 避免子类化,通过克隆创建新对象")
        print("3. 动态添加和删除产品")
        print("4. 保护原型对象不被修改")
        print("5. 运行时指定要实例化的类")
        print("=" * 60)


if __name__ == "__main__":
    PrototypePatternDemo.main()

运行结果:

bash 复制代码
> python.exe .\prototype_pattern.py                    
============================================================
原型模式演示
============================================================

1. 创建形状缓存并加载原型:
----------------------------------------
缓存加载完成!

2. 从缓存获取克隆对象:
----------------------------------------
获取形状: 圆形
形状ID: 1
绘制 圆形 [ID: 1]

获取形状: 矩形
形状ID: 2
绘制 矩形 [ID: 2]

获取形状: 正方形
形状ID: 3
绘制 正方形 [ID: 3]

3. 验证克隆对象是独立的:
----------------------------------------
克隆1 ID: 2015717635408
克隆2 ID: 2015717635504
是否为同一对象: False
是否相等: True

4. 修改克隆对象验证独立性:
----------------------------------------
修改后的克隆1 ID: 1-修改
新克隆3 ID: 1
原型未被修改: True

============================================================
原型模式的优势:
============================================================
1. 减少对象创建的开销(特别是创建成本高的对象)
2. 避免子类化,通过克隆创建新对象
3. 动态添加和删除产品
4. 保护原型对象不被修改
5. 运行时指定要实例化的类
============================================================

3. 结构型模式(Structural Patterns)(共7种)

总览表

模式 核心目的 使用场景 结构特点 关键操作
适配器 接口转换 集成不兼容的类/系统 包装器,转换接口 转换调用
桥接 抽象与实现分离 多维度独立变化 两个独立继承体系 委托调用
组合 部分-整体层次 树形结构,统一处理 递归结构,叶子+容器 递归遍历
装饰 动态添加功能 在不改变类的情况下增强 包装器,层层叠加 前后增强
外观 简化复杂接口 子系统太多,需要统一入口 高层接口,屏蔽细节 转发调用
享元 共享细粒度对象 大量相似对象,节省内存 对象池,分离内外状态 复用对象
代理 控制对象访问 延迟加载、权限控制、远程 替身,控制访问 控制转发

快速选择指南

复制代码
需要解决接口不兼容? → 适配器
需要抽象和实现独立变化? → 桥接
需要处理树形结构? → 组合
需要动态添加功能? → 装饰器
需要简化复杂系统? → 外观
需要节省内存(大量对象)? → 享元
需要控制访问对象? → 代理

易混淆模式对比

  • 装饰器 vs 代理:

    装饰器:增强功能,接口不变,层层叠加

    代理:控制访问,接口相同,一对一

  • 外观 vs 适配器:

    外观:简化多个子系统,提供新接口

    适配器:转换单个对象接口,保持接口语义

  • 桥接 vs 策略:

    桥接:两个维度独立变化(形状×颜色)

    策略:一个算法族,可互相替换(支付方式)

  • 组合 vs 装饰器:

    组合:处理树形结构,统一叶子和容器

    装饰器:包装单个对象,增强功能

3.1. 适配器模式(Adapter)

  • 概要

适配器模式是一种结构型设计模式,用于将一个类的接口转换为另一个类的接口。解决两个不兼容的接口之间的兼容问题,从而使它们能够协同工作。

组成组件:

目标接口(Target Interface):是客户端代码期望的接口。在适配器模式中,它通常由抽象类或接口 表示。

适配器(Adapter):是实现目标接口的对象。适配器通过包装一个需要适配的对象,并实现目标接口来实现适配的效果。

源接口(Adaptee Interface):是需要被适配的接口。在适配器模式中,它通常由一个或多个具体类或接口表示。

实现方式:

类适配器模式:通过继承来实现适配器,从而使适配器成为源接口的子类,并实现目标接口。这种方式需要适配器能够覆盖源接口的所有方法。

对象适配器模式:通过组合来实现适配器,从而使适配器持有一个源接口的对象,并实现目标接口。这种方式可以在适配器中自定义需要适配的方法,而无需覆盖源接口的所有方法。

优点:

能够解决两个不兼容接口之间的兼容问题,并且可以使代码更加灵活和可扩展。
缺点:

需要额外的适配器对象,可能会导致代码的复杂性增加。在设计过程中,需要根据具体的场景和需求,选择最合适的适配器实现方式。

  • 实现

首先创建目标接口,一个抽象类 MediaPlayer 和其派生类 AudioPlayer。默认情况下,AudioPlayer 可以播放 mp3 格式的音频文件。

然后创建源接口,另一个抽象类 AdvancedMediaPlayer 和其派生类 VlcPlayer 或者 Mp4Player。

第三创建适配器,创建一个实现了 MediaPlayer 接口的适配器类 MediaAdapter,并使用 AdvancedMediaPlayer 对象来播放所需的格式。

最后,想要让 AudioPlayer 播放其他格式(VLC,MP4)的音频文件,需要 AudioPlayer 使用适配器类 MediaAdapter.play() 并传递所需的音频类型,AudioPlayer 不需要知道能播放所需格式音频的实际类。AdapterPatternDemo 类使用 AudioPlayer 类来播放各种格式。

python 复制代码
"""
适配器模式 (Adapter Pattern)

媒体播放器案例:
- AudioPlayer 只能播放 mp3
- 通过适配器 MediaAdapter,AudioPlayer 也能播放 vlc 和 mp4
"""

from abc import ABC, abstractmethod


# ============ 目标接口 ============

class MediaPlayer(ABC):
    """
    媒体播放器接口(目标接口)
    
    客户端期望使用的统一接口
    """
    
    @abstractmethod
    def play(self, audio_type: str, file_name: str) -> None:
        """
        播放音频文件
        
        Args:
            audio_type: 音频类型 (mp3/vlc/mp4)
            file_name: 文件名
        """
        pass


# ============ 被适配者接口 ============

class AdvancedMediaPlayer(ABC):
    """
    高级媒体播放器接口(被适配者接口)
    
    需要被适配的接口
    """
    
    @abstractmethod
    def play_vlc(self, file_name: str) -> None:
        """播放 VLC 格式文件"""
        pass
    
    @abstractmethod
    def play_mp4(self, file_name: str) -> None:
        """播放 MP4 格式文件"""
        pass


# ============ 具体被适配者类 ============

class VlcPlayer(AdvancedMediaPlayer):
    """VLC 播放器"""
    
    def play_vlc(self, file_name: str) -> None:
        print(f"播放 vlc 文件: {file_name}")
    
    def play_mp4(self, file_name: str) -> None:
        # VLC 播放器不支持 MP4
        pass


class Mp4Player(AdvancedMediaPlayer):
    """MP4 播放器"""
    
    def play_vlc(self, file_name: str) -> None:
        # MP4 播放器不支持 VLC
        pass
    
    def play_mp4(self, file_name: str) -> None:
        print(f"播放 mp4 文件: {file_name}")


# ============ 适配器类 ============

class MediaAdapter(MediaPlayer):
    """
    媒体适配器类
    
    实现了 MediaPlayer 接口,内部使用 AdvancedMediaPlayer 对象
    将 MediaPlayer 接口适配到 AdvancedMediaPlayer 接口
    """
    
    def __init__(self, audio_type: str):
        """
        根据音频类型创建对应的高级播放器
        
        Args:
            audio_type: 音频类型 (vlc/mp4)
        """
        self.advanced_player: AdvancedMediaPlayer = None
        
        if audio_type.lower() == "vlc":
            self.advanced_player = VlcPlayer()
        elif audio_type.lower() == "mp4":
            self.advanced_player = Mp4Player()
    
    def play(self, audio_type: str, file_name: str) -> None:
        """
        使用高级播放器播放音频
        
        Args:
            audio_type: 音频类型
            file_name: 文件名
        """
        if audio_type.lower() == "vlc":
            self.advanced_player.play_vlc(file_name)
        elif audio_type.lower() == "mp4":
            self.advanced_player.play_mp4(file_name)


# ============ 客户端类 ============

class AudioPlayer(MediaPlayer):
    """
    音频播放器(客户端)
    
    只能直接播放 mp3,其他格式通过适配器播放
    """
    
    def __init__(self):
        self.media_adapter: MediaAdapter = None
    
    def play(self, audio_type: str, file_name: str) -> None:
        """
        播放音频文件
        
        内置支持 mp3,其他格式使用适配器
        
        Args:
            audio_type: 音频类型
            file_name: 文件名
        """
        # 内置支持 mp3 格式
        if audio_type.lower() == "mp3":
            print(f"播放 mp3 文件: {file_name}")
        
        # 使用适配器支持其他格式
        elif audio_type.lower() in ["vlc", "mp4"]:
            self.media_adapter = MediaAdapter(audio_type)
            self.media_adapter.play(audio_type, file_name)
        
        # 不支持的格式
        else:
            print(f"错误: 不支持 {audio_type} 格式")


# ============ 演示类 ============

class AdapterPatternDemo:
    """适配器模式演示类"""
    
    @staticmethod
    def main():
        """主方法 - 演示适配器模式的使用"""
        print("=" * 60)
        print("适配器模式演示 - 媒体播放器")
        print("=" * 60)
        
        # 创建音频播放器
        audio_player = AudioPlayer()
        
        print("\n1. 播放 MP3 格式(内置支持):")
        print("-" * 40)
        audio_player.play("mp3", "song.mp3")
        
        print("\n2. 播放 MP4 格式(通过适配器):")
        print("-" * 40)
        audio_player.play("mp4", "movie.mp4")
        
        print("\n3. 播放 VLC 格式(通过适配器):")
        print("-" * 40)
        audio_player.play("vlc", "video.vlc")
        
        print("\n4. 尝试播放不支持的格式:")
        print("-" * 40)
        audio_player.play("avi", "clip.avi")
        
        # 总结
        print("\n" + "=" * 60)
        print("适配器模式的优势:")
        print("=" * 60)
        print("1. 让不兼容的接口能够一起工作")
        print("2. 客户端不需要修改代码就能使用新功能")
        print("3. 复用了现有的类(VlcPlayer, Mp4Player)")
        print("4. 解耦了客户端和被适配者")
        print("=" * 60)


if __name__ == "__main__":
    AdapterPatternDemo.main()

运行结果:

bash 复制代码
> python.exe .\adapter_pattern.py                      
============================================================
适配器模式演示 - 媒体播放器
============================================================

1. 播放 MP3 格式(内置支持):
----------------------------------------
播放 mp3 文件: song.mp3

2. 播放 MP4 格式(通过适配器):
----------------------------------------
播放 mp4 文件: movie.mp4

3. 播放 VLC 格式(通过适配器):
----------------------------------------
播放 vlc 文件: video.vlc

4. 尝试播放不支持的格式:
----------------------------------------
错误: 不支持 avi 格式

============================================================
适配器模式的优势:
============================================================
1. 让不兼容的接口能够一起工作
2. 客户端不需要修改代码就能使用新功能
3. 复用了现有的类(VlcPlayer, Mp4Player)
4. 解耦了客户端和被适配者
============================================================

3.2. 桥接模式(Bridge)

  • 概要

桥接模式是一种结构型设计模式,旨在将抽象部分和具体实现部分分离,使它们可以独立地变化。

其原理实现是基于面向对象的多态特性,其核心思想是将抽象部分和实现部分解耦,使得它们可以独立地变化而互不影响

在桥接模式中,抽象部分和实现部分分别由抽象类和实现类来表示,它们之间通过一个桥梁接口来联系。

将抽象和实现解耦,各自独立变化 横向扩展(多维度)

实现步骤:

定义抽象类和实现类:抽象类定义了抽象部分的接口,包含了一些基本的方法。实现类定义了实现部分的接口,包含了一些实现方法。

定义桥梁接口:桥梁接口定义了抽象部分和实现部分之间的连接,它包含了一个对实现类的引用,以及一些委托方法。

定义具体桥梁类:具体桥梁类继承了桥梁接口,实现了委托方法,将调用转发给实现类的方法。

实例化具体桥梁类:在程序运行时,实例化具体桥梁类,并将实现类对象作为参数传递给具体桥梁类的构造函数。

调用具体桥梁类的方法:在程序运行时,调用具体桥梁类的方法,具体桥梁类将委托给实现类的方法来完成具体的操作。

  • 实现

首先,创建一个抽象接口 DrawAPI 和其派生类 RedCircle、GreenCircle。

定义桥梁接口 Shape(抽象类)和其派生类(理解为具体桥梁类)Circle,将使用 DrawAPI 的对象。总而言之:Circle 代理了(也理解为桥了) RedCircle 和 GreenCircle;抽象层和实现层都可以扩展,Shape(形状)通过 DrawAPI(颜色)独立变化,两者可以任意组合。

BridgePatternDemo 类使用 Shape 类来画出不同颜色的圆。

python 复制代码
"""
桥接模式 (Bridge Pattern)

将抽象与实现分离,使它们可以独立变化。
本例中:Shape(抽象)与 DrawAPI(实现)分离
"""

from abc import ABC, abstractmethod


# ============ 实现化角色 ============

class DrawAPI(ABC):
    """
    绘图 API 接口(实现化角色)
    
    定义实现类的接口,供抽象类调用
    """
    
    @abstractmethod
    def draw_circle(self, radius: int, x: int, y: int) -> None:
        """
        绘制圆形
        
        Args:
            radius: 半径
            x: 圆心 x 坐标
            y: 圆心 y 坐标
        """
        pass


# ============ 具体实现化角色 ============

class RedCircle(DrawAPI):
    """红色圆形绘制实现"""
    
    def draw_circle(self, radius: int, x: int, y: int) -> None:
        print(f"绘制红色圆形 [半径: {radius}, 圆心: ({x}, {y})]")


class GreenCircle(DrawAPI):
    """绿色圆形绘制实现"""
    
    def draw_circle(self, radius: int, x: int, y: int) -> None:
        print(f"绘制绿色圆形 [半径: {radius}, 圆心: ({x}, {y})]")


# ============ 抽象化角色 ============

class Shape(ABC):
    """
    形状抽象类(抽象化角色)
    
    持有 DrawAPI 对象的引用,将具体操作委托给实现类
    """
    
    def __init__(self, draw_api: DrawAPI):
        """
        初始化时注入 DrawAPI 实现对象
        
        Args:
            draw_api: 绘图 API 实现
        """
        self.draw_api = draw_api
    
    @abstractmethod
    def draw(self) -> None:
        """绘制形状"""
        pass


# ============ 扩展抽象化角色 ============

class Circle(Shape):
    """圆形类(扩展抽象化角色)"""
    
    def __init__(self, x: int, y: int, radius: int, draw_api: DrawAPI):
        """
        初始化圆形
        
        Args:
            x: 圆心 x 坐标
            y: 圆心 y 坐标
            radius: 半径
            draw_api: 绘图 API 实现
        """
        super().__init__(draw_api)
        self.x = x
        self.y = y
        self.radius = radius
    
    def draw(self) -> None:
        """绘制圆形 - 委托给 DrawAPI 实现"""
        self.draw_api.draw_circle(self.radius, self.x, self.y)


# ============ 演示类 ============

class BridgePatternDemo:
    """桥接模式演示类"""
    
    @staticmethod
    def main():
        """主方法 - 演示桥接模式的使用"""
        print("=" * 60)
        print("桥接模式演示")
        print("=" * 60)
        
        print("\n1. 创建红色圆形:")
        print("-" * 40)
        # 创建红色绘制 API
        red_api = RedCircle()
        # 创建圆形,注入红色 API
        red_circle = Circle(100, 100, 10, red_api)
        red_circle.draw()
        
        print("\n2. 创建绿色圆形:")
        print("-" * 40)
        # 创建绿色绘制 API
        green_api = GreenCircle()
        # 创建圆形,注入绿色 API
        green_circle = Circle(200, 200, 20, green_api)
        green_circle.draw()
        
        print("\n3. 创建多个不同颜色的圆形:")
        print("-" * 40)
        circles = [
            Circle(50, 50, 5, red_api),
            Circle(150, 150, 15, green_api),
            Circle(250, 250, 25, red_api),
            Circle(350, 350, 35, green_api),
        ]
        
        for i, circle in enumerate(circles, 1):
            print(f"圆形 {i}:")
            circle.draw()
        
        # 总结
        print("\n" + "=" * 60)
        print("桥接模式的优势:")
        print("=" * 60)
        print("1. 抽象和实现分离,可以独立扩展")
        print("2. 优秀的扩展能力")
        print("3. 隐藏实现细节,对客户端透明")
        print("4. 实现细节对客户透明")
        print("\n在本例中:")
        print("- Shape 是抽象,DrawAPI 是实现")
        print("- 可以独立添加新的形状(抽象扩展)")
        print("- 可以独立添加新的颜色(实现扩展)")
        print("- 两者通过组合而非继承连接")
        print("=" * 60)


if __name__ == "__main__":
    BridgePatternDemo.main()

运行结果:

bash 复制代码
> python.exe .\bridge_pattern.py                       
============================================================
桥接模式演示
============================================================

1. 创建红色圆形:
----------------------------------------
绘制红色圆形 [半径: 10, 圆心: (100, 100)]

2. 创建绿色圆形:
----------------------------------------
绘制绿色圆形 [半径: 20, 圆心: (200, 200)]

3. 创建多个不同颜色的圆形:
----------------------------------------
圆形 1:
绘制红色圆形 [半径: 5, 圆心: (50, 50)]
圆形 2:
绘制绿色圆形 [半径: 15, 圆心: (150, 150)]
圆形 3:
绘制红色圆形 [半径: 25, 圆心: (250, 250)]
圆形 4:
绘制绿色圆形 [半径: 35, 圆心: (350, 350)]

============================================================
桥接模式的优势:
============================================================
1. 抽象和实现分离,可以独立扩展
2. 优秀的扩展能力
3. 隐藏实现细节,对客户端透明
4. 实现细节对客户透明

在本例中:
- Shape 是抽象,DrawAPI 是实现
- 可以独立添加新的形状(抽象扩展)
- 可以独立添加新的颜色(实现扩展)
- 两者通过组合而非继承连接
============================================================

3.3. 组合模式(Composite)

  • 概要

组合模式是一种结构型设计模式,它允许将对象组合成树形结构来表示整体------部分关系,使得客户端可以统一处理单个对象和组合对象。

包含以下角色:

抽象组件(Component):定义了组合中所有对象共有的行为,并规定了管理子组件的方法。

叶子组件(Leaf):表示组合中的单个对象,叶子节点没有子节点。

容器组件(Composite):表示组合中的容器对象,容器节点可以包含其他容器节点和叶子节点。

客户端(Client):通过抽象组件操作组合对象。

优点:

使用组合模式可以使得客户端可以像处理单个对象一样处理组合对象。

同时也方便了新增或删除子组件。

该模式通常应用于处理树形结构数据或者嵌套的对象结构。

  • 实现

一个类 Employee,该类被当作组合模型类。CompositePatternDemo 类使用 Employee 类来添加部门层次结构,并打印所有员工。

python 复制代码
"""
组合模式 (Composite Pattern)

将对象组合成树形结构以表示"部分-整体"的层次结构。
本例使用 Employee 类展示公司部门层次结构。
"""

from typing import List, Optional


class Employee:
    """
    员工类(组合模式模型类)
    
    既可以是叶子节点(普通员工),也可以是组合节点(经理/主管)
    """
    
    def __init__(self, name: str, dept: str, salary: float):
        """
        初始化员工
        
        Args:
            name: 姓名
            dept: 部门
            salary: 薪水
        """
        self.name = name
        self.dept = dept
        self.salary = salary
        self.subordinates: List[Employee] = []
    
    def add(self, employee: 'Employee') -> None:
        """
        添加下属
        
        Args:
            employee: 下属员工
        """
        self.subordinates.append(employee)
    
    def remove(self, employee: 'Employee') -> None:
        """
        移除下属
        
        Args:
            employee: 要移除的下属
        """
        self.subordinates.remove(employee)
    
    def get_subordinates(self) -> List['Employee']:
        """获取下属列表"""
        return self.subordinates
    
    def __str__(self) -> str:
        """返回员工信息字符串"""
        return f"员工: [姓名: {self.name}, 部门: {self.dept}, 薪水: {self.salary}]"
    
    def display(self, level: int = 0) -> None:
        """
        递归显示员工及其所有下属
        
        Args:
            level: 层级缩进级别
        """
        indent = "  " * level
        print(f"{indent}{self}")
        
        for subordinate in self.subordinates:
            subordinate.display(level + 1)
    
    def get_total_salary(self) -> float:
        """
        递归计算该员工及其所有下属的总薪水
        
        Returns:
            总薪水
        """
        total = self.salary
        for subordinate in self.subordinates:
            total += subordinate.get_total_salary()
        return total
    
    def get_employee_count(self) -> int:
        """
        递归计算该员工及其所有下属的总人数
        
        Returns:
            总人数
        """
        count = 1  # 自己
        for subordinate in self.subordinates:
            count += subordinate.get_employee_count()
        return count


# ============ 演示类 ============

class CompositePatternDemo:
    """组合模式演示类"""
    
    @staticmethod
    def main():
        """主方法 - 演示组合模式的使用"""
        print("=" * 60)
        print("组合模式演示 - 公司部门层次结构")
        print("=" * 60)
        
        # 创建 CEO(顶级节点)
        print("\n1. 创建 CEO:")
        print("-" * 40)
        ceo = Employee("张三", "CEO", 50000)
        print(ceo)
        
        # 创建部门主管(CEO的下属)
        print("\n2. 添加部门主管:")
        print("-" * 40)
        
        # 技术部主管
        tech_head = Employee("李四", "技术部", 30000)
        print(f"添加: {tech_head}")
        ceo.add(tech_head)
        
        # 市场部主管
        marketing_head = Employee("王五", "市场部", 30000)
        print(f"添加: {marketing_head}")
        ceo.add(marketing_head)
        
        # 财务部主管
        finance_head = Employee("赵六", "财务部", 28000)
        print(f"添加: {finance_head}")
        ceo.add(finance_head)
        
        # 添加技术人员(技术部主管的下属)
        print("\n3. 添加技术人员:")
        print("-" * 40)
        
        developer1 = Employee("小明", "技术部-前端", 15000)
        print(f"添加: {developer1}")
        tech_head.add(developer1)
        
        developer2 = Employee("小红", "技术部-后端", 16000)
        print(f"添加: {developer2}")
        tech_head.add(developer2)
        
        developer3 = Employee("小刚", "技术部-测试", 14000)
        print(f"添加: {developer3}")
        tech_head.add(developer3)
        
        # 添加市场人员(市场部主管的下属)
        print("\n4. 添加市场人员:")
        print("-" * 40)
        
        marketer1 = Employee("小丽", "市场部-销售", 12000)
        print(f"添加: {marketer1}")
        marketing_head.add(marketer1)
        
        marketer2 = Employee("小强", "市场部-推广", 13000)
        print(f"添加: {marketer2}")
        marketing_head.add(marketer2)
        
        # 添加财务人员(财务部主管的下属)
        print("\n5. 添加财务人员:")
        print("-" * 40)
        
        accountant = Employee("小芳", "财务部-会计", 11000)
        print(f"添加: {accountant}")
        finance_head.add(accountant)
        
        # 显示完整层次结构
        print("\n" + "=" * 60)
        print("6. 显示完整的部门层次结构:")
        print("=" * 60)
        ceo.display()
        
        # 统计信息
        print("\n" + "=" * 60)
        print("7. 统计信息:")
        print("=" * 60)
        print(f"公司总人数: {ceo.get_employee_count()} 人")
        print(f"公司总薪水: {ceo.get_total_salary():.2f} 元")
        print(f"\n技术部人数: {tech_head.get_employee_count()} 人")
        print(f"技术部总薪水: {tech_head.get_total_salary():.2f} 元")
        print(f"\n市场部人数: {marketing_head.get_employee_count()} 人")
        print(f"市场部总薪水: {marketing_head.get_total_salary():.2f} 元")
        
        # 总结
        print("\n" + "=" * 60)
        print("组合模式的优势:")
        print("=" * 60)
        print("1. 统一处理单个对象和组合对象(叶子和容器)")
        print("2. 可以构建复杂的树形结构")
        print("3. 容易新增新的组件类型")
        print("4. 简化客户端代码,无需区分单个对象和组合对象")
        print("\n在本例中:")
        print("- Employee 既是叶子节点(普通员工)")
        print("- 也是组合节点(经理/主管包含下属)")
        print("- 可以统一调用 display() 方法显示整个层次结构")
        print("=" * 60)


if __name__ == "__main__":
    CompositePatternDemo.main()

运行结果:

bash 复制代码
> python.exe .\composite_pattern.py                    
============================================================
组合模式演示 - 公司部门层次结构
============================================================

1. 创建 CEO:
----------------------------------------
员工: [姓名: 张三, 部门: CEO, 薪水: 50000]

2. 添加部门主管:
----------------------------------------
添加: 员工: [姓名: 李四, 部门: 技术部, 薪水: 30000]
添加: 员工: [姓名: 王五, 部门: 市场部, 薪水: 30000]
添加: 员工: [姓名: 赵六, 部门: 财务部, 薪水: 28000]

3. 添加技术人员:
----------------------------------------
添加: 员工: [姓名: 小明, 部门: 技术部-前端, 薪水: 15000]
添加: 员工: [姓名: 小红, 部门: 技术部-后端, 薪水: 16000]
添加: 员工: [姓名: 小刚, 部门: 技术部-测试, 薪水: 14000]

4. 添加市场人员:
----------------------------------------
添加: 员工: [姓名: 小丽, 部门: 市场部-销售, 薪水: 12000]
添加: 员工: [姓名: 小强, 部门: 市场部-推广, 薪水: 13000]

5. 添加财务人员:
----------------------------------------
添加: 员工: [姓名: 小芳, 部门: 财务部-会计, 薪水: 11000]

============================================================
6. 显示完整的部门层次结构:
============================================================
员工: [姓名: 张三, 部门: CEO, 薪水: 50000]
  员工: [姓名: 李四, 部门: 技术部, 薪水: 30000]
    员工: [姓名: 小明, 部门: 技术部-前端, 薪水: 15000]
    员工: [姓名: 小红, 部门: 技术部-后端, 薪水: 16000]
    员工: [姓名: 小刚, 部门: 技术部-测试, 薪水: 14000]
  员工: [姓名: 王五, 部门: 市场部, 薪水: 30000]
    员工: [姓名: 小丽, 部门: 市场部-销售, 薪水: 12000]
    员工: [姓名: 小强, 部门: 市场部-推广, 薪水: 13000]
  员工: [姓名: 赵六, 部门: 财务部, 薪水: 28000]
    员工: [姓名: 小芳, 部门: 财务部-会计, 薪水: 11000]

============================================================
7. 统计信息:
============================================================
公司总人数: 10 人
公司总薪水: 219000.00 元

技术部人数: 4 人
技术部总薪水: 75000.00 元

市场部人数: 3 人
市场部总薪水: 55000.00 元

============================================================
组合模式的优势:
============================================================
1. 统一处理单个对象和组合对象(叶子和容器)
2. 可以构建复杂的树形结构
3. 容易新增新的组件类型
4. 简化客户端代码,无需区分单个对象和组合对象

在本例中:
- Employee 既是叶子节点(普通员工)
- 也是组合节点(经理/主管包含下属)
- 可以统一调用 display() 方法显示整个层次结构
============================================================

3.4. 装饰模式(Decorator)

  • 概要

装饰模式是一种结构型设计模式,它允许在运行时为对象动态添加功能。装饰模式是一种替代继承的方式,它通过将对象放入包装器对象中来实现这一点。这种模式是开放封闭原则的一种具体实现方式。

装饰 增强 - 给对象动态添加额外功能 纵向叠加(功能层叠)

装饰模式的核心思想是,在不改变原有类的情况下,通过包装原有类来扩展其功能。这使得我们可以在运行时动态地添加功能,而不需要在编译时修改代码。

在装饰模式中,可以通过组合的方式来添加多个装饰器,从而实现对对象的多次装饰。

同时,装饰器对象可以嵌套在其他装饰器对象内部,从而形成一个装饰器对象的树形结构,这种结构称为装饰器链。

在执行操作时,装饰器对象会按照一定的顺序递归地调用装饰器链中的操作方法。

组成组件:

抽象组件(Component)类:定义了基本的操作方法。

具体组件(ConcreteComponent)类:实现了抽象组件类中定义的操作方法。

装饰器(Decorator)类:也实现了抽象组件类中定义的操作方法,并且它包含一个指向抽象组件类的引用。

具体装饰器(ConcreteDecorator)类:扩展了装饰器类,以实现额外的功能。

  • 实现

创建一个抽象类 Shape 和实现了 Shape 接口的实体类。

然后创建一个实现了 Shape 接口的抽象装饰类 ShapeDecorator,并把 Shape 对象作为它的实例变量。RedShapeDecorator 是实现了 ShapeDecorator 的实体类。

DecoratorPatternDemo 类使用 RedShapeDecorator 来装饰 Shape 对象。

python 复制代码
"""
装饰器模式 (Decorator Pattern)

动态地给一个对象添加一些额外的职责。
本例中:为形状添加红色边框装饰。
"""

from abc import ABC, abstractmethod


# ============ 组件接口 ============

class Shape(ABC):
    """
    形状接口(组件接口)
    
    定义了形状的基本操作
    """
    
    @abstractmethod
    def draw(self) -> None:
        """绘制形状"""
        pass


# ============ 具体组件 ============

class Circle(Shape):
    """圆形类"""
    
    def draw(self) -> None:
        print("绘制圆形")


class Rectangle(Shape):
    """矩形类"""
    
    def draw(self) -> None:
        print("绘制矩形")


# ============ 抽象装饰类 ============

class ShapeDecorator(Shape, ABC):
    """
    形状装饰器抽象类
    
    实现了 Shape 接口,并持有 Shape 对象作为实例变量
    """
    
    def __init__(self, decorated_shape: Shape):
        """
        初始化装饰器
        
        Args:
            decorated_shape: 被装饰的形状对象
        """
        self.decorated_shape = decorated_shape
    
    def draw(self) -> None:
        """调用被装饰对象的 draw 方法"""
        self.decorated_shape.draw()


# ============ 具体装饰类 ============

class RedShapeDecorator(ShapeDecorator):
    """
    红色形状装饰器
    
    为形状添加红色边框
    """
    
    def __init__(self, decorated_shape: Shape):
        """
        初始化红色装饰器
        
        Args:
            decorated_shape: 被装饰的形状对象
        """
        super().__init__(decorated_shape)
    
    def draw(self) -> None:
        """
        绘制带红色边框的形状
        
        先调用父类的 draw 方法绘制原形状,
        然后添加红色边框
        """
        self.decorated_shape.draw()
        self.set_red_border()
    
    def set_red_border(self) -> None:
        """设置红色边框"""
        print("边框颜色: 红色")


# ============ 演示类 ============

class DecoratorPatternDemo:
    """装饰器模式演示类"""
    
    @staticmethod
    def main():
        """主方法 - 演示装饰器模式的使用"""
        print("=" * 60)
        print("装饰器模式演示 - 形状装饰")
        print("=" * 60)
        
        # 1. 创建普通形状
        print("\n1. 创建普通形状(无装饰):")
        print("-" * 40)
        
        circle = Circle()
        print("普通圆形:")
        circle.draw()
        
        print()
        
        rectangle = Rectangle()
        print("普通矩形:")
        rectangle.draw()
        
        # 2. 使用红色装饰器装饰形状
        print("\n2. 使用红色装饰器装饰形状:")
        print("-" * 40)
        
        red_circle = RedShapeDecorator(circle)
        print("红色圆形:")
        red_circle.draw()
        
        print()
        
        red_rectangle = RedShapeDecorator(rectangle)
        print("红色矩形:")
        red_rectangle.draw()
        
        # 3. 多重装饰(装饰器可以嵌套)
        print("\n3. 多重装饰(演示装饰器可叠加):")
        print("-" * 40)
        
        # 可以多次装饰(虽然本例中 RedShapeDecorator 不能叠加出不同效果)
        # 实际应用中可以有多个不同的装饰器叠加
        print("注意: 装饰器可以嵌套使用")
        print("例如: 红色边框 + 阴影效果 + 渐变填充")
        
        # 总结
        print("\n" + "=" * 60)
        print("装饰器模式的优势:")
        print("=" * 60)
        print("1. 在不改变原有对象的情况下动态添加功能")
        print("2. 可以用多个装饰器叠加功能")
        print("3. 遵循开闭原则(对扩展开放,对修改关闭)")
        print("4. 比继承更灵活,可以在运行时添加/移除功能")
        print("\n在本例中:")
        print("- Shape 是组件接口")
        print("- Circle/Rectangle 是具体组件")
        print("- ShapeDecorator 是抽象装饰器")
        print("- RedShapeDecorator 是具体装饰器,添加了红色边框")
        print("=" * 60)


if __name__ == "__main__":
    DecoratorPatternDemo.main()

运行结果:

bash 复制代码
> python.exe .\decorator_pattern.py
============================================================
装饰器模式演示 - 形状装饰
============================================================

1. 创建普通形状(无装饰):
----------------------------------------
普通圆形:
绘制圆形

普通矩形:
绘制矩形

2. 使用红色装饰器装饰形状:
----------------------------------------
红色圆形:
绘制圆形
边框颜色: 红色

红色矩形:
绘制矩形
边框颜色: 红色

3. 多重装饰(演示装饰器可叠加):
----------------------------------------
注意: 装饰器可以嵌套使用
例如: 红色边框 + 阴影效果 + 渐变填充

============================================================
装饰器模式的优势:
============================================================
1. 在不改变原有对象的情况下动态添加功能
2. 可以用多个装饰器叠加功能
3. 遵循开闭原则(对扩展开放,对修改关闭)
4. 比继承更灵活,可以在运行时添加/移除功能

在本例中:
- Shape 是组件接口
- Circle/Rectangle 是具体组件
- ShapeDecorator 是抽象装饰器
- RedShapeDecorator 是具体装饰器,添加了红色边框
============================================================

3.5. 外观模式(Facade)

  • 概要

外观模式是一种结构型设计模式,它提供了一个简单的接口,隐藏了一个或多个复杂的子系统的复杂性。

外观模式可以使得客户端只需要与外观对象进行交互,而不需要与子系统中的每个对象直接交互,从而降低了客户端的复杂性,提高了系统的可维护性。

实现思路:

外观模式的核心思想是,提供一个简单的接口,包装一个或多个复杂的子系统,隐藏其复杂性,并向客户端提供一个更简单、更易于使用的接口。

在外观模式中,外观对象扮演着客户端和子系统之间的协调者,它负责将客户端的请求转发给子系统中的相应对象,并将其结果返回给客户端。

优点:

简化了客户端的使用:外观模式为客户端提供了一个简单的接口,使得客户端不需要了解子系统中的每个对象及其功能,从而降低了客户端的复杂性。

隐藏了子系统的复杂性:外观模式将子系统的复杂性隐藏在外观对象之后,使得客户端只需要与外观对象进行交互,从而提高了系统的可维护性。

提高了灵活性:由于客户端只与外观对象进行交互,因此可以在不影响客户端的情况下修改或替换子系统中的对象。

缺点:

不能完全隐藏子系统的复杂性:外观模式只是将子系统的复杂性隐藏在外观对象之后,但仍然需要客户端了解外观对象的接口和使用方式。

可能会引入不必要的复杂性:如果外观对象需要处理复杂的逻辑,就会引入额外的复杂性,从而降低系统的可维护性。

  • 实现

创建一个抽象接口 Shape 和其派生类。

下一步是定义一个外观类 ShapeMaker。ShapeMaker 类使用实体类来代表用户对这些类的调用。

FacadePatternDemo 类使用 ShapeMaker 类来显示结果。

python 复制代码
"""
外观模式 (Facade Pattern)

为子系统中的一组接口提供一个统一的高层接口,
使得子系统更容易使用。
"""

from abc import ABC, abstractmethod


# ============ 子系统类 ============

class Shape(ABC):
    """形状接口"""
    
    @abstractmethod
    def draw(self) -> None:
        """绘制形状"""
        pass


class Circle(Shape):
    """圆形类"""
    
    def draw(self) -> None:
        print("绘制圆形")


class Rectangle(Shape):
    """矩形类"""
    
    def draw(self) -> None:
        print("绘制矩形")


class Square(Shape):
    """正方形类"""
    
    def draw(self) -> None:
        print("绘制正方形")


# ============ 外观类 ============

class ShapeMaker:
    """
    形状制造者(外观类)
    
    为形状绘制系统提供一个简化的统一接口
    """
    
    def __init__(self):
        """初始化外观类,创建所有形状对象"""
        self.circle = Circle()
        self.rectangle = Rectangle()
        self.square = Square()
    
    def draw_circle(self) -> None:
        """绘制圆形"""
        self.circle.draw()
    
    def draw_rectangle(self) -> None:
        """绘制矩形"""
        self.rectangle.draw()
    
    def draw_square(self) -> None:
        """绘制正方形"""
        self.square.draw()
    
    def draw_all(self) -> None:
        """绘制所有形状"""
        print("绘制所有形状:")
        self.circle.draw()
        self.rectangle.draw()
        self.square.draw()


# ============ 演示类 ============

class FacadePatternDemo:
    """外观模式演示类"""
    
    @staticmethod
    def main():
        """主方法 - 演示外观模式的使用"""
        print("=" * 60)
        print("外观模式演示")
        print("=" * 60)
        
        # 创建外观对象
        print("\n1. 创建外观对象 ShapeMaker")
        print("-" * 40)
        shape_maker = ShapeMaker()
        
        # 使用外观类绘制各种形状
        print("\n2. 使用外观类绘制单个形状:")
        print("-" * 40)
        
        print("绘制圆形:")
        shape_maker.draw_circle()
        
        print("\n绘制矩形:")
        shape_maker.draw_rectangle()
        
        print("\n绘制正方形:")
        shape_maker.draw_square()
        
        # 一键绘制所有形状
        print("\n3. 一键绘制所有形状:")
        print("-" * 40)
        shape_maker.draw_all()
        
        # 对比:不使用外观类的情况
        print("\n4. 对比 - 不使用外观类时的调用方式:")
        print("-" * 40)
        print("需要分别创建和管理每个形状对象:")
        print("  circle = Circle()")
        print("  rectangle = Rectangle()")
        print("  square = Square()")
        print("  circle.draw()")
        print("  rectangle.draw()")
        print("  square.draw()")
        print("\n使用外观类后,只需:")
        print("  shape_maker = ShapeMaker()")
        print("  shape_maker.draw_all()")
        
        # 总结
        print("\n" + "=" * 60)
        print("外观模式的优势:")
        print("=" * 60)
        print("1. 简化接口 - 客户端只需与外观类交互")
        print("2. 解耦 - 减少客户端与子系统的依赖")
        print("3. 更好的分层 - 有助于建立清晰的系统层次结构")
        print("4. 提供统一入口 - 隐藏子系统的复杂性")
        print("\n在本例中:")
        print("- Shape/Circle/Rectangle/Square 是子系统")
        print("- ShapeMaker 是外观类,提供简化接口")
        print("- 客户端只需调用 ShapeMaker 的方法,无需直接操作子系统")
        print("=" * 60)


if __name__ == "__main__":
    FacadePatternDemo.main()

运行结果:

bash 复制代码
> python.exe .\facade_pattern.py                       
============================================================
外观模式演示
============================================================

1. 创建外观对象 ShapeMaker
----------------------------------------

2. 使用外观类绘制单个形状:
----------------------------------------
绘制圆形:
绘制圆形

绘制矩形:
绘制矩形

绘制正方形:
绘制正方形

3. 一键绘制所有形状:
----------------------------------------
绘制所有形状:
绘制圆形
绘制矩形
绘制正方形

4. 对比 - 不使用外观类时的调用方式:
----------------------------------------
需要分别创建和管理每个形状对象:
  circle = Circle()
  rectangle = Rectangle()
  square = Square()
  circle.draw()
  rectangle.draw()
  square.draw()

使用外观类后,只需:
  shape_maker = ShapeMaker()
  shape_maker.draw_all()

============================================================
外观模式的优势:
============================================================
1. 简化接口 - 客户端只需与外观类交互
2. 解耦 - 减少客户端与子系统的依赖
3. 更好的分层 - 有助于建立清晰的系统层次结构
4. 提供统一入口 - 隐藏子系统的复杂性

在本例中:
- Shape/Circle/Rectangle/Square 是子系统
- ShapeMaker 是外观类,提供简化接口
- 客户端只需调用 ShapeMaker 的方法,无需直接操作子系统
============================================================

3.6. 享元模式(Flyweight)

  • 概要

享元模式是一种结构型设计模式,它通过共享对象来尽可能减少内存使用和对象数量。

在享元模式中,存在两种对象:内部状态和外部状态。内部状态指对象的共享部分,不随环境改变而改变;外部状态指对象的非共享部分,会随环境改变而改变。

实现思路:

享元模式的核心思想是尽量重用已经存在的对象,减少对象的创建和销毁,从而提高性能和节省内存。

它通常适用于需要大量创建对象的场景,但又不能因为对象过多而导致内存不足或性能降低的情况。

  • 实现

创建一个抽象接口 Shape 和其派生类 Circle。

下一步是定义工厂类 ShapeFactory。ShapeFactory 有一个 Circle 的 HashMap,其中键名为 Circle 对象的颜色。无论何时接收到请求,都会创建一个特定颜色的圆。ShapeFactory 检查它的 HashMap 中的 circle 对象,如果找到 Circle 对象,则返回该对象,否则将创建一个存储在 hashmap 中以备后续使用的新对象,并把该对象返回到客户端。

FlyWeightPatternDemo 类使用 ShapeFactory 来获取 Shape 对象。它将向 ShapeFactory 传递信息(red / green / blue/ black / white),以便获取它所需对象的颜色。

python 复制代码
"""
享元模式 (Flyweight Pattern)

运用共享技术有效地支持大量细粒度的对象。
本例中:共享 Circle 对象,避免重复创建相同颜色的圆。
"""

from abc import ABC, abstractmethod
from typing import Dict


# ============ 享元接口 ============

class Shape(ABC):
    """形状接口(享元接口)"""
    
    @abstractmethod
    def draw(self, x: int, y: int) -> None:
        """
        绘制形状
        
        Args:
            x: x 坐标(外部状态)
            y: y 坐标(外部状态)
        """
        pass


# ============ 具体享元类 ============

class Circle(Shape):
    """
    圆形类(具体享元)
    
    包含内部状态(color)和外部状态(x, y)
    """
    
    def __init__(self, color: str):
        """
        初始化圆形
        
        Args:
            color: 颜色(内部状态)
        """
        self.color = color  # 内部状态:可以共享
        self.x = 0          # 外部状态:由客户端传入
        self.y = 0          # 外部状态:由客户端传入
    
    def set_x(self, x: int) -> None:
        """设置 x 坐标"""
        self.x = x
    
    def set_y(self, y: int) -> None:
        """设置 y 坐标"""
        self.y = y
    
    def draw(self, x: int, y: int) -> None:
        """
        绘制圆形
        
        Args:
            x: x 坐标(外部状态)
            y: y 坐标(外部状态)
        """
        self.x = x
        self.y = y
        print(f"绘制圆形: [颜色: {self.color}, 位置: ({x}, {y})]")


# ============ 享元工厂 ============

class ShapeFactory:
    """
    形状工厂(享元工厂)
    
    管理和创建享元对象,确保相同颜色的圆只创建一个实例
    """
    
    # 类属性:存储享元对象的 HashMap(字典)
    circle_map: Dict[str, Circle] = {}
    
    @classmethod
    def get_circle(cls, color: str) -> Circle:
        """
        获取指定颜色的圆形
        
        如果该颜色的圆已存在,返回缓存的实例;
        否则创建新实例并缓存。
        
        Args:
            color: 颜色
            
        Returns:
            Circle: 圆形对象
        """
        circle = cls.circle_map.get(color)
        
        if circle is None:
            # 创建新的享元对象
            circle = Circle(color)
            cls.circle_map[color] = circle
            print(f"创建新的 {color} 圆形")
        else:
            print(f"复用已有的 {color} 圆形")
        
        return circle
    
    @classmethod
    def get_circle_count(cls) -> int:
        """获取已创建的圆形数量"""
        return len(cls.circle_map)
    
    @classmethod
    def print_all_circles(cls) -> None:
        """打印所有已创建的圆形"""
        print(f"\n已创建的圆形总数: {cls.get_circle_count()}")
        print("包含的颜色:", list(cls.circle_map.keys()))


# ============ 演示类 ============

class FlyweightPatternDemo:
    """享元模式演示类"""
    
    @staticmethod
    def main():
        """主方法 - 演示享元模式的使用"""
        print("=" * 60)
        print("享元模式演示")
        print("=" * 60)
        
        colors = ["red", "green", "blue", "black", "white"]
        
        print("\n1. 创建不同颜色的圆形(首次创建):")
        print("-" * 40)
        
        # 首次创建各种颜色的圆
        for color in colors:
            circle = ShapeFactory.get_circle(color)
            circle.draw(10, 20)
        
        # 查看已创建的圆
        ShapeFactory.print_all_circles()
        
        # 再次请求相同颜色的圆(应该复用)
        print("\n2. 再次请求相同颜色的圆形(复用已有对象):")
        print("-" * 40)
        
        for color in colors:
            circle = ShapeFactory.get_circle(color)
            circle.draw(30, 40)
        
        # 再次查看已创建的圆(数量应该不变)
        ShapeFactory.print_all_circles()
        
        # 模拟创建大量对象
        print("\n3. 模拟创建大量对象(展示享元模式的优势):")
        print("-" * 40)
        
        import random
        
        print("随机创建 20 个圆形(只有 5 种颜色):")
        for i in range(20):
            color = random.choice(colors)
            x = random.randint(0, 100)
            y = random.randint(0, 100)
            
            circle = ShapeFactory.get_circle(color)
            circle.draw(x, y)
        
        # 最终统计
        ShapeFactory.print_all_circles()
        
        # 总结
        print("\n" + "=" * 60)
        print("享元模式的优势:")
        print("=" * 60)
        print("1. 减少内存占用 - 共享相同的对象")
        print("2. 提高性能 - 避免重复创建对象")
        print("3. 分离内部状态和外部状态")
        print("4. 适用于大量相似对象的场景")
        print("\n在本例中:")
        print("- Circle 是享元类,color 是内部状态(可共享)")
        print("- x, y 是外部状态(由客户端传入)")
        print("- ShapeFactory 是享元工厂,管理享元对象池")
        print("- 虽然创建了 30 个圆形,但只有 5 个实际对象")
        print("=" * 60)


if __name__ == "__main__":
    FlyweightPatternDemo.main()

运行结果:

bash 复制代码
> python.exe .\flyweight_pattern.py                    
============================================================
享元模式演示
============================================================

1. 创建不同颜色的圆形(首次创建):
----------------------------------------
创建新的 red 圆形
绘制圆形: [颜色: red, 位置: (10, 20)]
创建新的 green 圆形
绘制圆形: [颜色: green, 位置: (10, 20)]
创建新的 blue 圆形
绘制圆形: [颜色: blue, 位置: (10, 20)]
创建新的 black 圆形
绘制圆形: [颜色: black, 位置: (10, 20)]
创建新的 white 圆形
绘制圆形: [颜色: white, 位置: (10, 20)]

已创建的圆形总数: 5
包含的颜色: ['red', 'green', 'blue', 'black', 'white']

2. 再次请求相同颜色的圆形(复用已有对象):
----------------------------------------
复用已有的 red 圆形
绘制圆形: [颜色: red, 位置: (30, 40)]
复用已有的 green 圆形
绘制圆形: [颜色: green, 位置: (30, 40)]
复用已有的 blue 圆形
绘制圆形: [颜色: blue, 位置: (30, 40)]
复用已有的 black 圆形
绘制圆形: [颜色: black, 位置: (30, 40)]
复用已有的 white 圆形
绘制圆形: [颜色: white, 位置: (30, 40)]

已创建的圆形总数: 5
包含的颜色: ['red', 'green', 'blue', 'black', 'white']

3. 模拟创建大量对象(展示享元模式的优势):
----------------------------------------
随机创建 20 个圆形(只有 5 种颜色):
复用已有的 white 圆形
绘制圆形: [颜色: white, 位置: (61, 12)]
复用已有的 blue 圆形
绘制圆形: [颜色: blue, 位置: (46, 30)]
复用已有的 white 圆形
绘制圆形: [颜色: white, 位置: (77, 78)]
复用已有的 green 圆形
绘制圆形: [颜色: green, 位置: (20, 53)]
复用已有的 white 圆形
绘制圆形: [颜色: white, 位置: (33, 31)]
复用已有的 black 圆形
绘制圆形: [颜色: black, 位置: (75, 29)]
复用已有的 black 圆形
绘制圆形: [颜色: black, 位置: (96, 33)]
复用已有的 green 圆形
绘制圆形: [颜色: green, 位置: (31, 18)]
复用已有的 green 圆形
绘制圆形: [颜色: green, 位置: (29, 55)]
复用已有的 blue 圆形
绘制圆形: [颜色: blue, 位置: (53, 93)]
复用已有的 green 圆形
绘制圆形: [颜色: green, 位置: (39, 89)]
复用已有的 white 圆形
绘制圆形: [颜色: white, 位置: (49, 96)]
复用已有的 green 圆形
绘制圆形: [颜色: green, 位置: (52, 10)]
复用已有的 white 圆形
绘制圆形: [颜色: white, 位置: (75, 28)]
复用已有的 green 圆形
绘制圆形: [颜色: green, 位置: (26, 72)]
复用已有的 white 圆形
绘制圆形: [颜色: white, 位置: (0, 82)]
复用已有的 black 圆形
绘制圆形: [颜色: black, 位置: (57, 13)]
复用已有的 red 圆形
绘制圆形: [颜色: red, 位置: (32, 86)]
复用已有的 green 圆形
绘制圆形: [颜色: green, 位置: (12, 26)]
复用已有的 green 圆形
绘制圆形: [颜色: green, 位置: (36, 91)]

已创建的圆形总数: 5
包含的颜色: ['red', 'green', 'blue', 'black', 'white']

============================================================
享元模式的优势:
============================================================
1. 减少内存占用 - 共享相同的对象
2. 提高性能 - 避免重复创建对象
3. 分离内部状态和外部状态
4. 适用于大量相似对象的场景

在本例中:
- Circle 是享元类,color 是内部状态(可共享)
- x, y 是外部状态(由客户端传入)
- ShapeFactory 是享元工厂,管理享元对象池
- 虽然创建了 30 个圆形,但只有 5 个实际对象
============================================================

3.7. 代理模式(Proxy)

  • 概要

代理模式是一种结构型设计模式,它允许在访问对象时添加一些额外的行为。

代理类充当客户端和实际对象之间的中介。客户端通过代理来访问实际对象,代理在访问实际对象前后执行一些额外的操作,例如权限检查、缓存等。

包含三个角色:抽象主题(Subject)、真实主题(Real Subject)和代理主题(Proxy Subject)。其中,抽象主题定义了真实主题和代理主题的公共接口;真实主题是实际执行操作的对象;代理主题通过实现抽象主题接口,控制对真实主题的访问。

  • 实现

创建一个抽象接口 Image 和其派生类。ProxyImage 是一个代理类,减少 RealImage 对象加载的内存占用。

ProxyPatternDemo 类使用 ProxyImage 来获取要加载的 Image 对象,并按照需求进行显示。

python 复制代码
"""
代理模式 (Proxy Pattern) - 虚拟代理

为其他对象提供一种代理以控制对这个对象的访问。
本例中:ProxyImage 代理 RealImage,实现延迟加载,减少内存占用。
"""

from abc import ABC, abstractmethod
from typing import Optional
import time


# ============ 主题接口 ============

class Image(ABC):
    """
    图片接口(主题接口)
    
    定义了 RealImage 和 ProxyImage 的共同接口
    """
    
    @abstractmethod
    def display(self) -> None:
        """显示图片"""
        pass


# ============ 真实主题 ============

class RealImage(Image):
    """
    真实图片类
    
    真正加载和显示图片的类,加载过程耗时且占用内存
    """
    
    def __init__(self, file_name: str):
        """
        初始化真实图片
        
        Args:
            file_name: 图片文件名
        """
        self.file_name = file_name
        self.load_from_disk()
    
    def load_from_disk(self) -> None:
        """
        从磁盘加载图片
        
        这是一个耗时且占用内存的操作
        """
        print(f"正在加载图片: {self.file_name} ...")
        time.sleep(1)  # 模拟加载耗时
        print(f"图片 {self.file_name} 加载完成!")
    
    def display(self) -> None:
        """显示图片"""
        print(f"显示图片: {self.file_name}")


# ============ 代理 ============

class ProxyImage(Image):
    """
    图片代理类
    
    代理 RealImage,实现延迟加载:
    - 第一次调用 display() 时才创建 RealImage 对象
    - 后续调用直接复用已创建的 RealImage
    """
    
    def __init__(self, file_name: str):
        """
        初始化代理图片
        
        Args:
            file_name: 图片文件名
        """
        self.file_name = file_name
        self.real_image: Optional[RealImage] = None  # 延迟初始化
    
    def display(self) -> None:
        """
        显示图片
        
        如果 RealImage 未创建,则先创建;
        如果已创建,则直接复用。
        """
        if self.real_image is None:
            print(f"代理: 首次请求 {self.file_name},需要加载")
            self.real_image = RealImage(self.file_name)
        else:
            print(f"代理: {self.file_name} 已加载,直接显示")
        
        self.real_image.display()


# ============ 演示类 ============

class ProxyPatternDemo:
    """代理模式演示类"""
    
    @staticmethod
    def main():
        """主方法 - 演示代理模式的使用"""
        print("=" * 60)
        print("代理模式演示 - 图片代理(虚拟代理)")
        print("=" * 60)
        
        print("\n1. 创建代理对象(不加载图片):")
        print("-" * 40)
        
        # 创建代理对象,此时不加载真实图片
        image1 = ProxyImage("photo1.jpg")
        image2 = ProxyImage("photo2.jpg")
        
        print(f"代理对象1创建完成: {image1.file_name}")
        print(f"代理对象2创建完成: {image2.file_name}")
        print("注意:此时图片并未加载到内存中!")
        
        # 第一次显示图片(触发加载)
        print("\n2. 第一次显示 photo1.jpg(触发加载):")
        print("-" * 40)
        image1.display()
        
        # 再次显示同一图片(复用)
        print("\n3. 再次显示 photo1.jpg(直接复用):")
        print("-" * 40)
        image1.display()
        
        # 显示另一张图片
        print("\n4. 第一次显示 photo2.jpg(触发加载):")
        print("-" * 40)
        image2.display()
        
        # 再次显示
        print("\n5. 再次显示 photo2.jpg(直接复用):")
        print("-" * 40)
        image2.display()
        
        # 对比:直接使用 RealImage
        print("\n6. 对比 - 直接使用 RealImage:")
        print("-" * 40)
        print("创建 RealImage 对象时会立即加载图片:")
        real_image = RealImage("photo3.jpg")
        real_image.display()
        
        # 总结
        print("\n" + "=" * 60)
        print("代理模式的优势:")
        print("=" * 60)
        print("1. 延迟加载(懒加载)- 减少启动时间和内存占用")
        print("2. 访问控制 - 代理可以控制对真实对象的访问")
        print("3. 远程代理 - 隐藏对象位于不同地址空间的事实")
        print("4. 保护代理 - 控制访问权限")
        print("\n在本例中(虚拟代理):")
        print("- Image 是主题接口")
        print("- RealImage 是真实主题,加载图片耗时耗内存")
        print("- ProxyImage 是代理,延迟创建 RealImage")
        print("- 客户端通过代理使用图片,无需关心加载细节")
        print("\n内存对比:")
        print("- 使用代理:未显示的图片不占用内存")
        print("- 不使用代理:所有图片立即加载,占用大量内存")
        print("=" * 60)


if __name__ == "__main__":
    ProxyPatternDemo.main()

运行结果:

bash 复制代码
> python.exe .\proxy_pattern.py
============================================================
代理模式演示 - 图片代理(虚拟代理)
============================================================

1. 创建代理对象(不加载图片):
----------------------------------------
代理对象1创建完成: photo1.jpg
代理对象2创建完成: photo2.jpg
注意:此时图片并未加载到内存中!

2. 第一次显示 photo1.jpg(触发加载):
----------------------------------------
代理: 首次请求 photo1.jpg,需要加载
正在加载图片: photo1.jpg ...
图片 photo1.jpg 加载完成!
显示图片: photo1.jpg

3. 再次显示 photo1.jpg(直接复用):
----------------------------------------
代理: photo1.jpg 已加载,直接显示
显示图片: photo1.jpg

4. 第一次显示 photo2.jpg(触发加载):
----------------------------------------
代理: 首次请求 photo2.jpg,需要加载
正在加载图片: photo2.jpg ...
图片 photo2.jpg 加载完成!
显示图片: photo2.jpg

5. 再次显示 photo2.jpg(直接复用):
----------------------------------------
代理: photo2.jpg 已加载,直接显示
显示图片: photo2.jpg

6. 对比 - 直接使用 RealImage:
----------------------------------------
创建 RealImage 对象时会立即加载图片:
正在加载图片: photo3.jpg ...
图片 photo3.jpg 加载完成!
显示图片: photo3.jpg

============================================================
代理模式的优势:
============================================================
1. 延迟加载(懒加载)- 减少启动时间和内存占用
2. 访问控制 - 代理可以控制对真实对象的访问
3. 远程代理 - 隐藏对象位于不同地址空间的事实
4. 保护代理 - 控制访问权限

在本例中(虚拟代理):
- Image 是主题接口
- RealImage 是真实主题,加载图片耗时耗内存
- ProxyImage 是代理,延迟创建 RealImage
- 客户端通过代理使用图片,无需关心加载细节

内存对比:
- 使用代理:未显示的图片不占用内存
- 不使用代理:所有图片立即加载,占用大量内存
============================================================

4. 行为型模式(Behavioral Patterns)(共11种)

总览表

模式 核心目的 使用场景 关键角色 一句话总结
责任链 请求沿链传递,直到被处理 多级审批、日志级别过滤 Handler、ConcreteHandler 踢皮球,直到有人接盘
命令 将请求封装为对象 撤销/重做、任务队列、宏命令 Command、Invoker、Receiver 将动作打包成快递单
解释器 定义文法并解释执行 DSL解析、表达式求值 Expression、Terminal/NonTerminal 语言翻译官
迭代器 顺序访问集合元素 遍历复杂数据结构 Iterator、Aggregate 让遍历与集合分离
中介者 封装对象间的交互 聊天室、表单协调、MVC Mediator、Colleague 群聊群主
备忘录 捕获并保存对象状态 撤销/重做、游戏存档、事务 Originator、Memento、CareTaker 时光机存档
观察者 状态变更通知依赖者 事件监听、发布订阅、MVC Subject、Observer 广播电台
状态 状态改变时改变行为 状态机、订单状态、游戏角色 State、Context 变色龙
策略 封装算法族,互相替换 支付方式、排序算法、路由策略 Strategy、Context 换工具不换人
模板方法 定义算法骨架,延迟实现 算法框架、流程标准化 AbstractClass、ConcreteClass 菜谱模板
访问者 分离操作与对象结构 编译器、报表生成、对象遍历 Visitor、Element 外科医生

快速选择指南

复制代码
需要处理请求但不确定由谁处理? → 责任链
需要撤销/重做/队列化操作? → 命令
需要解析自定义语言? → 解释器
需要遍历集合但不暴露内部? → 迭代器
对象间复杂交互需要解耦? → 中介者
需要保存/恢复历史状态? → 备忘录
状态变更需要通知多个对象? → 观察者
对象行为随状态改变? → 状态
需要在运行时切换算法? → 策略
需要固定流程但步骤可变? → 模板方法
需要给对象结构添加新操作? → 访问者

易混淆模式对比

  • 观察者 vs 中介者:
    观察者:一对多广播,Subject状态变化自动通知
    中介者:多对多协调,Colleague主动请求转发
  • 策略 vs 状态:
    策略:客户端选择算法,算法之间不自动切换
    状态:状态内部决定下一个状态,自动转换
  • 命令 vs 策略:
    命令:封装完整请求(含接收者),支持撤销
    策略:封装算法,关注计算逻辑
  • 访问者 vs 策略:
    访问者:操作不同类的对象,双分派
    策略:操作同类对象,单分派
  • 模板方法 vs 策略:
    模板方法:继承,固定流程
    策略:组合,替换算法

4.1. 职任链模式(Chain of Responsibility)

  • 概要

职责链模式是一种行为型设计模式,它通过将请求的发送者和接收者解耦,从而使多个对象都有机会处理这个请求。

实现思路:

在职责链模式中,需要定义一系列的处理器对象,每个对象都包含对下一个对象的引用。

当请求发送到处理器对象时,第一个处理器对象会尝试处理请求,如果它不能处理请求,则将请求传递给下一个处理器对象,以此类推,直到请求被处理或者所有的处理器对象都不能处理请求。

优点:

它可以灵活地配置处理器对象的顺序和组合,从而满足不同的处理需求。它还可以将请求的发送者和接收者解耦,从而提高系统的灵活性和可扩展性。
缺点:

如果处理器对象过多或者处理器对象之间的关系过于复杂,可能会导致系统的维护难度增加。

角色:

处理器接口(Handler Interface):定义处理器对象的接口,包含处理请求的方法和对下一个处理器对象的引用。

具体处理器类(Concrete Handlers):实现处理器接口,处理请求或将请求传递给下一个处理器对象。

客户端(Client):创建处理器对象的链,将请求发送给链的第一个处理器对象。

  • 实现

创建抽象类 AbstractLogger,带有详细的日志记录级别。

然后创建三种类型的记录器,都扩展了 AbstractLogger。每个记录器消息的级别是否属于自己的级别,如果是则相应地打印出来,否则将不打印并把消息传给下一个记录器。

python 复制代码
"""
责任链模式 (Chain of Responsibility Pattern)

为请求创建一个接收者对象的链,每个接收者都包含对另一个接收者的引用。
如果一个对象不能处理该请求,那么它会把相同的请求传给下一个接收者。
本例中:日志记录器链,根据日志级别决定由哪个记录器处理。
"""

from abc import ABC, abstractmethod
from enum import IntEnum


# ============ 日志级别枚举 ============

class LogLevel(IntEnum):
    """日志级别"""
    INFO = 1
    DEBUG = 2
    ERROR = 3


# ============ 抽象处理者 ============

class AbstractLogger(ABC):
    """
    抽象日志记录器
    
    定义处理请求的接口,并维护下一个处理者的引用
    """
    
    def __init__(self, level: LogLevel):
        """
        初始化日志记录器
        
        Args:
            level: 该记录器能处理的日志级别
        """
        self.level = level
        self.next_logger: 'AbstractLogger' = None
    
    def set_next_logger(self, next_logger: 'AbstractLogger') -> 'AbstractLogger':
        """
        设置下一个日志记录器
        
        Args:
            next_logger: 下一个记录器
            
        Returns:
            AbstractLogger: 返回下一个记录器,支持链式调用
        """
        self.next_logger = next_logger
        return next_logger
    
    def log_message(self, level: LogLevel, message: str) -> None:
        """
        记录日志消息
        
        如果消息的级别等于或高于当前记录器的级别,则处理;
        否则传递给下一个记录器。
        
        Args:
            level: 消息级别
            message: 消息内容
        """
        if self.level.value <= level.value:
            self.write(message)
        
        if self.next_logger is not None:
            self.next_logger.log_message(level, message)
    
    @abstractmethod
    def write(self, message: str) -> None:
        """
        写入日志(由具体记录器实现)
        
        Args:
            message: 消息内容
        """
        pass


# ============ 具体处理者 ============

class ConsoleLogger(AbstractLogger):
    """控制台日志记录器 - 处理 INFO 级别"""
    
    def __init__(self):
        super().__init__(LogLevel.INFO)
    
    def write(self, message: str) -> None:
        print(f"[INFO] 标准控制台::Logger: {message}")


class FileLogger(AbstractLogger):
    """文件日志记录器 - 处理 DEBUG 级别"""
    
    def __init__(self):
        super().__init__(LogLevel.DEBUG)
    
    def write(self, message: str) -> None:
        print(f"[DEBUG] 文件::Logger: {message}")


class ErrorLogger(AbstractLogger):
    """错误日志记录器 - 处理 ERROR 级别"""
    
    def __init__(self):
        super().__init__(LogLevel.ERROR)
    
    def write(self, message: str) -> None:
        print(f"[ERROR] 错误控制台::Logger: {message}")


# ============ 演示类 ============

class ChainPatternDemo:
    """责任链模式演示类"""
    
    @staticmethod
    def get_chain_of_loggers() -> AbstractLogger:
        """
        获取日志记录器链
        
        构建责任链:ErrorLogger -> FileLogger -> ConsoleLogger
        注意:链条顺序决定了处理优先级
        
        Returns:
            AbstractLogger: 链的第一个记录器
        """
        error_logger = ErrorLogger()
        file_logger = FileLogger()
        console_logger = ConsoleLogger()
        
        # 构建责任链
        error_logger.set_next_logger(file_logger).set_next_logger(console_logger)
        
        return error_logger
    
    @staticmethod
    def main():
        """主方法 - 演示责任链模式的使用"""
        print("=" * 60)
        print("责任链模式演示 - 日志记录器链")
        print("=" * 60)
        
        # 获取记录器链
        logger_chain = ChainPatternDemo.get_chain_of_loggers()
        
        print("\n日志记录器链结构:")
        print("-" * 40)
        print("ERROR -> DEBUG -> INFO")
        print("(错误日志) -> (文件日志) -> (控制台日志)")
        
        # 发送 INFO 级别消息
        print("\n1. 发送 INFO 级别消息:")
        print("-" * 40)
        logger_chain.log_message(LogLevel.INFO, "这是一条普通信息")
        
        # 发送 DEBUG 级别消息
        print("\n2. 发送 DEBUG 级别消息:")
        print("-" * 40)
        logger_chain.log_message(LogLevel.DEBUG, "这是一条调试信息")
        
        # 发送 ERROR 级别消息
        print("\n3. 发送 ERROR 级别消息:")
        print("-" * 40)
        logger_chain.log_message(LogLevel.ERROR, "这是一条错误信息")
        
        # 总结
        print("\n" + "=" * 60)
        print("责任链模式的优势:")
        print("=" * 60)
        print("1. 解耦发送者和接收者")
        print("2. 可以动态改变处理链")
        print("3. 增强给对象指派职责的灵活性")
        print("4. 符合单一职责原则")
        print("\n在本例中:")
        print("- AbstractLogger 是抽象处理者")
        print("- ConsoleLogger/FileLogger/ErrorLogger 是具体处理者")
        print("- 消息沿着责任链传递,直到被处理")
        print("- 每个记录器决定是否处理,或传递给下一个")
        print("=" * 60)


if __name__ == "__main__":
    ChainPatternDemo.main()

运行结果:

bash 复制代码
> python.exe .\chain_pattern.py                        
============================================================
责任链模式演示 - 日志记录器链
============================================================

日志记录器链结构:
----------------------------------------
ERROR -> DEBUG -> INFO
(错误日志) -> (文件日志) -> (控制台日志)

1. 发送 INFO 级别消息:
----------------------------------------
[INFO] 标准控制台::Logger: 这是一条普通信息

2. 发送 DEBUG 级别消息:
----------------------------------------
[DEBUG] 文件::Logger: 这是一条调试信息
[INFO] 标准控制台::Logger: 这是一条调试信息

3. 发送 ERROR 级别消息:
----------------------------------------
[ERROR] 错误控制台::Logger: 这是一条错误信息
[DEBUG] 文件::Logger: 这是一条错误信息
[INFO] 标准控制台::Logger: 这是一条错误信息

============================================================
责任链模式的优势:
============================================================
1. 解耦发送者和接收者
2. 可以动态改变处理链
3. 增强给对象指派职责的灵活性
4. 符合单一职责原则

在本例中:
- AbstractLogger 是抽象处理者
- ConsoleLogger/FileLogger/ErrorLogger 是具体处理者
- 消息沿着责任链传递,直到被处理
- 每个记录器决定是否处理,或传递给下一个
============================================================

4.2. 命令模式(Command)

  • 概要

命令模式是一种行为型设计模式,它将请求封装成一个对象,可以将不同的请求与其请求的接收者分开。

该模式的目的是通过将请求发送者和请求接收者解耦来实现请求的发送、执行和撤销等操作。

角色:

Command 接口:定义了一个执行命令的方法 execute。

Concrete Command 类(具体命令):实现了 Command 接口,实现 execute 方法,包含一个接收者对象,执行具体的业务逻辑。

Receiver 类:包含一些特定于应用程序的业务逻辑,实际执行命令。

Invoker 类:负责发送命令,它包含一个 Command 对象,可以在需要时调用该对象的 execute 方法。

  • 实现

首先,创建作为命令的接口 Order,执行接口 execute() ,其派生类 BuyStock 实现 execute() 具体调用 buy();SellStock 实现 execute() 具体调用 sell()。

然后,创建接收者,Stock(股票) 实体类,包含可执行命令 buy() 和 sell()。

第三,创建调用者,Broker(经纪人),它接受订单并能下订单,Broker 对象使用命令模式,基于命令的类型确定哪个对象执行哪个命令。

CommandPatternDemo 类使用 Broker 类来演示命令模式。

python 复制代码
"""
命令模式 (Command Pattern)

将请求封装成对象,从而可以用不同的请求、队列或日志来参数化其他对象。
本例中:股票交易命令系统。
"""

from abc import ABC, abstractmethod
from typing import List


# ============ 命令接口 ============

class Order(ABC):
    """
    订单接口(命令接口)
    
    定义执行命令的方法
    """
    
    @abstractmethod
    def execute(self) -> None:
        """执行命令"""
        pass


# ============ 接收者 ============

class Stock:
    """
    股票类(接收者)
    
    知道如何实施与执行一个请求相关的操作
    """
    
    def __init__(self, name: str, quantity: int):
        """
        初始化股票
        
        Args:
            name: 股票名称
            quantity: 股票数量
        """
        self.name = name
        self.quantity = quantity
    
    def buy(self) -> None:
        """买入股票"""
        print(f"买入股票 [名称: {self.name}, 数量: {self.quantity}]")
    
    def sell(self) -> None:
        """卖出股票"""
        print(f"卖出股票 [名称: {self.name}, 数量: {self.quantity}]")


# ============ 具体命令 ============

class BuyStock(Order):
    """
    买入股票命令
    
    将买入操作封装为命令对象
    """
    
    def __init__(self, stock: Stock):
        """
        初始化买入命令
        
        Args:
            stock: 股票对象
        """
        self.stock = stock
    
    def execute(self) -> None:
        """执行买入操作"""
        self.stock.buy()


class SellStock(Order):
    """
    卖出股票命令
    
    将卖出操作封装为命令对象
    """
    
    def __init__(self, stock: Stock):
        """
        初始化卖出命令
        
        Args:
            stock: 股票对象
        """
        self.stock = stock
    
    def execute(self) -> None:
        """执行卖出操作"""
        self.stock.sell()


# ============ 调用者 ============

class Broker:
    """
    经纪人类(调用者)
    
    接受订单并执行命令
    """
    
    def __init__(self):
        """初始化经纪人"""
        self.order_list: List[Order] = []
    
    def take_order(self, order: Order) -> None:
        """
        接受订单
        
        Args:
            order: 命令对象
        """
        self.order_list.append(order)
    
    def place_orders(self) -> None:
        """执行所有订单"""
        for order in self.order_list:
            order.execute()
        self.order_list.clear()


# ============ 演示类 ============

class CommandPatternDemo:
    """命令模式演示类"""
    
    @staticmethod
    def main():
        """主方法 - 演示命令模式的使用"""
        print("=" * 60)
        print("命令模式演示 - 股票交易系统")
        print("=" * 60)
        
        # 创建股票对象(接收者)
        print("\n1. 创建股票对象:")
        print("-" * 40)
        
        stock1 = Stock("阿里巴巴", 100)
        stock2 = Stock("腾讯", 50)
        stock3 = Stock("苹果", 200)
        
        print(f"股票1: {stock1.name}, 数量: {stock1.quantity}")
        print(f"股票2: {stock2.name}, 数量: {stock2.quantity}")
        print(f"股票3: {stock3.name}, 数量: {stock3.quantity}")
        
        # 创建命令对象
        print("\n2. 创建命令对象:")
        print("-" * 40)
        
        buy_stock1 = BuyStock(stock1)
        sell_stock2 = SellStock(stock2)
        buy_stock3 = BuyStock(stock3)
        sell_stock1 = SellStock(stock1)
        
        print("创建命令:")
        print("  - 买入阿里巴巴")
        print("  - 卖出腾讯")
        print("  - 买入苹果")
        print("  - 卖出阿里巴巴")
        
        # 创建经纪人(调用者)
        print("\n3. 创建经纪人并接收订单:")
        print("-" * 40)
        
        broker = Broker()
        broker.take_order(buy_stock1)
        broker.take_order(sell_stock2)
        broker.take_order(buy_stock3)
        broker.take_order(sell_stock1)
        
        print("经纪人已接收 4 个订单")
        
        # 执行订单
        print("\n4. 执行所有订单:")
        print("-" * 40)
        broker.place_orders()
        
        # 演示延迟执行和撤销
        print("\n5. 演示命令队列(批量执行):")
        print("-" * 40)
        
        # 添加新订单
        broker.take_order(BuyStock(Stock("谷歌", 150)))
        broker.take_order(SellStock(Stock("亚马逊", 80)))
        broker.take_order(BuyStock(Stock("微软", 120)))
        
        print("新增 3 个订单,准备批量执行:")
        broker.place_orders()
        
        # 总结
        print("\n" + "=" * 60)
        print("命令模式的优势:")
        print("=" * 60)
        print("1. 解耦调用者和接收者")
        print("2. 命令可以被参数化、队列化和日志化")
        print("3. 支持撤销和重做操作")
        print("4. 支持组合命令(宏命令)")
        print("\n在本例中:")
        print("- Order 是命令接口")
        print("- BuyStock/SellStock 是具体命令")
        print("- Stock 是接收者,执行实际操作")
        print("- Broker 是调用者,管理命令队列")
        print("- 命令将请求封装,使 Broker 无需知道具体股票细节")
        print("=" * 60)


if __name__ == "__main__":
    CommandPatternDemo.main()

运行结果:

bash 复制代码
> python.exe .\command_pattern.py                      
============================================================
命令模式演示 - 股票交易系统
============================================================

1. 创建股票对象:
----------------------------------------
股票1: 阿里巴巴, 数量: 100
股票2: 腾讯, 数量: 50
股票3: 苹果, 数量: 200

2. 创建命令对象:
----------------------------------------
创建命令:
  - 买入阿里巴巴
  - 卖出腾讯
  - 买入苹果
  - 卖出阿里巴巴

3. 创建经纪人并接收订单:
----------------------------------------
经纪人已接收 4 个订单

4. 执行所有订单:
----------------------------------------
买入股票 [名称: 阿里巴巴, 数量: 100]
卖出股票 [名称: 腾讯, 数量: 50]
买入股票 [名称: 苹果, 数量: 200]
卖出股票 [名称: 阿里巴巴, 数量: 100]

5. 演示命令队列(批量执行):
----------------------------------------
新增 3 个订单,准备批量执行:
买入股票 [名称: 谷歌, 数量: 150]
卖出股票 [名称: 亚马逊, 数量: 80]
买入股票 [名称: 微软, 数量: 120]

============================================================
命令模式的优势:
============================================================
1. 解耦调用者和接收者
2. 命令可以被参数化、队列化和日志化
3. 支持撤销和重做操作
4. 支持组合命令(宏命令)

在本例中:
- Order 是命令接口
- BuyStock/SellStock 是具体命令
- Stock 是接收者,执行实际操作
- Broker 是调用者,管理命令队列
- 命令将请求封装,使 Broker 无需知道具体股票细节
============================================================

4.3. 解释器模式(Interpreter)

  • 概要

解释器模式是一种行为型设计模式,它定义了一种语言文法,以及一个解释器,用于解释该语言中的句子。

解释器模式通常用于解决特定类型的问题,例如解释计算器表达式,SQL 查询语句等。

角色:

Context(上下文):它是解释器的运行环境。它存储解释器所需的一些全局信息。

Abstract Expression(抽象表达式):它是定义所有表达式的接口,通常包含解释方法 interpret()。

Concrete Expression(具体表达式):它实现抽象表达式接口,用于解释特定类型的表达式。

  • 实现

创建一个接口 Expression 和实现了 Expression 接口的实体类。

定义作为上下文中主要解释器的 TerminalExpression 类。其他的类 OrExpression、AndExpression 用于创建组合式表达式。

InterpreterPatternDemo,我们的演示类使用 Expression 类创建规则和演示表达式的解析。

python 复制代码
"""
解释器模式 (Interpreter Pattern)

给定一个语言,定义它的文法表示,并定义一个解释器,
这个解释器使用该表示来解释语言中的句子。
本例中:简单的规则表达式解析(AND/OR 逻辑)。
"""

from abc import ABC, abstractmethod
from typing import List


# ============ 抽象表达式 ============

class Expression(ABC):
    """
    表达式接口(抽象表达式)
    
    定义解释器的接口
    """
    
    @abstractmethod
    def interpret(self, context: str) -> bool:
        """
        解释方法
        
        Args:
            context: 上下文(待解释的文本)
            
        Returns:
            bool: 解释结果
        """
        pass


# ============ 终结符表达式 ============

class TerminalExpression(Expression):
    """
    终结符表达式
    
    实现与文法中的终结符相关的解释操作
    """
    
    def __init__(self, data: str):
        """
        初始化终结符表达式
        
        Args:
            data: 要匹配的数据
        """
        self.data = data
    
    def interpret(self, context: str) -> bool:
        """
        解释终结符
        
        检查上下文是否包含该终结符
        
        Args:
            context: 上下文文本
            
        Returns:
            bool: 是否包含
        """
        return self.data in context


# ============ 非终结符表达式 ============

class OrExpression(Expression):
    """
    或表达式(非终结符表达式)
    
    实现 OR 逻辑的解释操作
    """
    
    def __init__(self, expr1: Expression, expr2: Expression):
        """
        初始化或表达式
        
        Args:
            expr1: 第一个表达式
            expr2: 第二个表达式
        """
        self.expr1 = expr1
        self.expr2 = expr2
    
    def interpret(self, context: str) -> bool:
        """
        解释或表达式
        
        只要其中一个表达式为真,结果就为真
        
        Args:
            context: 上下文文本
            
        Returns:
            bool: 解释结果
        """
        return self.expr1.interpret(context) or self.expr2.interpret(context)


class AndExpression(Expression):
    """
    与表达式(非终结符表达式)
    
    实现 AND 逻辑的解释操作
    """
    
    def __init__(self, expr1: Expression, expr2: Expression):
        """
        初始化与表达式
        
        Args:
            expr1: 第一个表达式
            expr2: 第二个表达式
        """
        self.expr1 = expr1
        self.expr2 = expr2
    
    def interpret(self, context: str) -> bool:
        """
        解释与表达式
        
        两个表达式都为真,结果才为真
        
        Args:
            context: 上下文文本
            
        Returns:
            bool: 解释结果
        """
        return self.expr1.interpret(context) and self.expr2.interpret(context)


# ============ 演示类 ============

class InterpreterPatternDemo:
    """解释器模式演示类"""
    
    @staticmethod
    def get_male_expression() -> Expression:
        """
        获取男性表达式规则
        
        Returns:
            Expression: Robert OR John
        """
        robert = TerminalExpression("Robert")
        john = TerminalExpression("John")
        return OrExpression(robert, john)
    
    @staticmethod
    def get_married_woman_expression() -> Expression:
        """
        获取已婚女性表达式规则
        
        Returns:
            Expression: Julie AND Married
        """
        julie = TerminalExpression("Julie")
        married = TerminalExpression("Married")
        return AndExpression(julie, married)
    
    @staticmethod
    def get_complex_expression() -> Expression:
        """
        获取复杂表达式规则
        
        Returns:
            Expression: (Robert OR John) AND (Developer OR Manager)
        """
        # 创建人名表达式
        robert = TerminalExpression("Robert")
        john = TerminalExpression("John")
        
        # 创建职位表达式
        developer = TerminalExpression("Developer")
        manager = TerminalExpression("Manager")
        
        # 组合:Robert OR John
        person = OrExpression(robert, john)
        
        # 组合:Developer OR Manager
        position = OrExpression(developer, manager)
        
        # 最终组合:(Robert OR John) AND (Developer OR Manager)
        return AndExpression(person, position)
    
    @staticmethod
    def main():
        """主方法 - 演示解释器模式的使用"""
        print("=" * 60)
        print("解释器模式演示 - 规则表达式解析")
        print("=" * 60)
        
        # 获取规则表达式
        is_male = InterpreterPatternDemo.get_male_expression()
        is_married_woman = InterpreterPatternDemo.get_married_woman_expression()
        is_developer_or_manager = InterpreterPatternDemo.get_complex_expression()
        
        print("\n1. 测试男性表达式 (Robert OR John):")
        print("-" * 40)
        
        context1 = "John is male"
        context2 = "Robert is male"
        context3 = "Julie is female"
        
        print(f"上下文: '{context1}'")
        print(f"结果: {is_male.interpret(context1)} (期望: True)")
        
        print(f"\n上下文: '{context2}'")
        print(f"结果: {is_male.interpret(context2)} (期望: True)")
        
        print(f"\n上下文: '{context3}'")
        print(f"结果: {is_male.interpret(context3)} (期望: False)")
        
        print("\n2. 测试已婚女性表达式 (Julie AND Married):")
        print("-" * 40)
        
        context4 = "Julie is Married"
        context5 = "Julie is single"
        context6 = "Robert is Married"
        
        print(f"上下文: '{context4}'")
        print(f"结果: {is_married_woman.interpret(context4)} (期望: True)")
        
        print(f"\n上下文: '{context5}'")
        print(f"结果: {is_married_woman.interpret(context5)} (期望: False)")
        
        print(f"\n上下文: '{context6}'")
        print(f"结果: {is_married_woman.interpret(context6)} (期望: False)")
        
        print("\n3. 测试复杂表达式 ((Robert OR John) AND (Developer OR Manager)):")
        print("-" * 40)
        
        context7 = "Robert is a Developer"
        context8 = "John is a Manager"
        context9 = "Julie is a Developer"
        context10 = "Robert is a Designer"
        
        print(f"上下文: '{context7}'")
        print(f"结果: {is_developer_or_manager.interpret(context7)} (期望: True)")
        
        print(f"\n上下文: '{context8}'")
        print(f"结果: {is_developer_or_manager.interpret(context8)} (期望: True)")
        
        print(f"\n上下文: '{context9}'")
        print(f"结果: {is_developer_or_manager.interpret(context9)} (期望: False)")
        
        print(f"\n上下文: '{context10}'")
        print(f"结果: {is_developer_or_manager.interpret(context10)} (期望: False)")
        
        # 总结
        print("\n" + "=" * 60)
        print("解释器模式的优势:")
        print("=" * 60)
        print("1. 易于改变和扩展文法")
        print("2. 实现文法较为容易")
        print("3. 增加新的解释表达式较为方便")
        print("\n在本例中:")
        print("- Expression 是抽象表达式接口")
        print("- TerminalExpression 是终结符表达式(基本元素)")
        print("- OrExpression/AndExpression 是非终结符表达式(组合元素)")
        print("- 通过组合可以构建复杂的规则表达式")
        print("- 每个表达式都知道如何解释自己")
        print("=" * 60)


if __name__ == "__main__":
    InterpreterPatternDemo.main()

运行结果:

bash 复制代码
> python.exe .\interpreter_pattern.py
============================================================
解释器模式演示 - 规则表达式解析
============================================================

1. 测试男性表达式 (Robert OR John):
----------------------------------------
上下文: 'John is male'
结果: True (期望: True)

上下文: 'Robert is male'
结果: True (期望: True)

上下文: 'Julie is female'
结果: False (期望: False)

2. 测试已婚女性表达式 (Julie AND Married):
----------------------------------------
上下文: 'Julie is Married'
结果: True (期望: True)

上下文: 'Julie is single'
结果: False (期望: False)

上下文: 'Robert is Married'
结果: False (期望: False)

3. 测试复杂表达式 ((Robert OR John) AND (Developer OR Manager)):
----------------------------------------
上下文: 'Robert is a Developer'
结果: True (期望: True)

上下文: 'John is a Manager'
结果: True (期望: True)

上下文: 'Julie is a Developer'
结果: False (期望: False)

上下文: 'Robert is a Designer'
结果: False (期望: False)

============================================================
解释器模式的优势:
============================================================
1. 易于改变和扩展文法
2. 实现文法较为容易
3. 增加新的解释表达式较为方便

在本例中:
- Expression 是抽象表达式接口
- TerminalExpression 是终结符表达式(基本元素)
- OrExpression/AndExpression 是非终结符表达式(组合元素)
- 通过组合可以构建复杂的规则表达式
- 每个表达式都知道如何解释自己
============================================================

4.4. 迭代器模式(Iterator)

  • 概要

迭代器模式是一种行为型设计模式,允许在不暴露集合底层实现的情况下遍历集合中的所有元素。

实现思路:

在迭代器模式中,集合类(如列表、树等)将遍历操作委托给一个迭代器对象,而不是直接实现遍历操作。

迭代器对象负责实现遍历操作,以及保存当前遍历位置等状态。

这样,集合类就可以将遍历操作与集合底层实现解耦,从而使得集合类更加简单、灵活和易于维护。

角色:

Iterator(迭代器):定义了迭代器的接口,包含用于遍历集合元素的方法,如 next()、has_next() 等。

ConcreteIterator(具体迭代器):实现了迭代器接口,负责实现迭代器的具体遍历逻辑,以及保存当前遍历位置等状态。

Aggregate(集合):定义了集合的接口,包含用于获取迭代器对象的方法,如 create_iterator() 等。

ConcreteAggregate(具体集合):实现了集合接口,负责创建具体迭代器对象,以便遍历集合中的元素。

优点:

将遍历操作与集合底层实现解耦,使得集合类更加灵活和易于维护。

简化了集合类的接口,使得集合类更加简单明了。

提供了对不同类型的集合统一遍历的机制,使得算法的复用性更加高。
缺点:

由于迭代器对象需要保存遍历位置等状态,因此它可能会占用比较大的内存。

此外,由于迭代器对象需要负责遍历逻辑,因此它可能会变得比较复杂。

  • 实现

创建一个叙述导航方法的 Iterator 接口和一个返回迭代器的 Container 接口。实现了 Container 接口的实体类将负责实现 Iterator 接口。

IteratorPatternDemo,我们的演示类使用实体类 NamesRepository 来打印 NamesRepository 中存储为集合的 Names。

python 复制代码
"""
迭代器模式 (Iterator Pattern)

提供一种方法顺序访问一个聚合对象中各个元素,
而又无需暴露该对象的内部表示。
"""

from abc import ABC, abstractmethod
from typing import Any, List


# ============ 迭代器接口 ============

class Iterator(ABC):
    """
    迭代器接口
    
    定义访问和遍历元素的接口
    """
    
    @abstractmethod
    def has_next(self) -> bool:
        """
        检查是否还有下一个元素
        
        Returns:
            bool: 如果有下一个元素返回 True
        """
        pass
    
    @abstractmethod
    def next(self) -> Any:
        """
        获取下一个元素
        
        Returns:
            Any: 下一个元素
            
        Raises:
            StopIteration: 如果没有更多元素
        """
        pass


# ============ 容器接口 ============

class Container(ABC):
    """
    容器接口
    
    定义获取迭代器的方法
    """
    
    @abstractmethod
    def get_iterator(self) -> Iterator:
        """
        获取迭代器
        
        Returns:
            Iterator: 迭代器对象
        """
        pass


# ============ 具体容器类 ============

class NamesRepository(Container):
    """
    名称存储库(具体容器)
    
    存储名称集合,并提供迭代器访问
    """
    
    def __init__(self):
        """初始化名称存储库"""
        self.names: List[str] = []
    
    def add_name(self, name: str) -> None:
        """
        添加名称
        
        Args:
            name: 名称
        """
        self.names.append(name)
    
    def get_iterator(self) -> Iterator:
        """
        获取名称迭代器
        
        Returns:
            Iterator: 名称迭代器
        """
        return NameIterator(self)


# ============ 具体迭代器类 ============

class NameIterator(Iterator):
    """
    名称迭代器(具体迭代器)
    
    实现遍历 NamesRepository 的逻辑
    """
    
    def __init__(self, repository: NamesRepository):
        """
        初始化迭代器
        
        Args:
            repository: 名称存储库
        """
        self.repository = repository
        self.index = 0
    
    def has_next(self) -> bool:
        """
        检查是否还有下一个名称
        
        Returns:
            bool: 如果有下一个名称返回 True
        """
        return self.index < len(self.repository.names)
    
    def next(self) -> str:
        """
        获取下一个名称
        
        Returns:
            str: 下一个名称
            
        Raises:
            StopIteration: 如果没有更多名称
        """
        if self.has_next():
            name = self.repository.names[self.index]
            self.index += 1
            return name
        else:
            raise StopIteration("没有更多元素")


# ============ 演示类 ============

class IteratorPatternDemo:
    """迭代器模式演示类"""
    
    @staticmethod
    def main():
        """主方法 - 演示迭代器模式的使用"""
        print("=" * 60)
        print("迭代器模式演示")
        print("=" * 60)
        
        # 创建名称存储库
        print("\n1. 创建名称存储库并添加名称:")
        print("-" * 40)
        
        names_repository = NamesRepository()
        names_repository.add_name("Robert")
        names_repository.add_name("John")
        names_repository.add_name("Julie")
        names_repository.add_name("Lora")
        
        print("已添加名称:")
        print("  - Robert")
        print("  - John")
        print("  - Julie")
        print("  - Lora")
        
        # 使用迭代器遍历
        print("\n2. 使用迭代器遍历名称:")
        print("-" * 40)
        
        iterator = names_repository.get_iterator()
        
        print("正向遍历:")
        count = 1
        while iterator.has_next():
            name = iterator.next()
            print(f"  {count}. {name}")
            count += 1
        
        # 演示多个迭代器独立工作
        print("\n3. 演示多个迭代器独立工作:")
        print("-" * 40)
        
        iterator1 = names_repository.get_iterator()
        iterator2 = names_repository.get_iterator()
        
        print("迭代器1遍历前两个:")
        print(f"  1. {iterator1.next()}")
        print(f"  2. {iterator1.next()}")
        
        print("\n迭代器2遍历全部:")
        count = 1
        while iterator2.has_next():
            print(f"  {count}. {iterator2.next()}")
            count += 1
        
        print("\n迭代器1继续遍历剩余:")
        count = 3
        while iterator1.has_next():
            print(f"  {count}. {iterator1.next()}")
            count += 1
        
        # 演示与其他容器的对比
        print("\n4. 与 Python 内置迭代器对比:")
        print("-" * 40)
        
        print("自定义迭代器:")
        for name in CustomIterable(names_repository.names):
            print(f"  {name}")
        
        print("\nPython 列表迭代:")
        for name in names_repository.names:
            print(f"  {name}")
        
        # 总结
        print("\n" + "=" * 60)
        print("迭代器模式的优势:")
        print("=" * 60)
        print("1. 支持以不同的方式遍历聚合对象")
        print("2. 迭代器简化了聚合接口")
        print("3. 在同一个聚合上可以有多个遍历")
        print("4. 迭代器模式分离了集合和遍历逻辑")
        print("\n在本例中:")
        print("- Iterator 是迭代器接口(has_next, next)")
        print("- Container 是容器接口(get_iterator)")
        print("- NamesRepository 是具体容器,存储名称")
        print("- NameIterator 是具体迭代器,实现遍历逻辑")
        print("- 客户端通过迭代器访问集合,无需知道内部结构")
        print("=" * 60)


# 辅助类:使自定义迭代器支持 for 循环
class CustomIterable:
    """使自定义迭代器支持 for 循环的辅助类"""
    
    def __init__(self, items: List[str]):
        self.items = items
        self.index = 0
    
    def __iter__(self):
        return self
    
    def __next__(self):
        if self.index < len(self.items):
            item = self.items[self.index]
            self.index += 1
            return item
        raise StopIteration


if __name__ == "__main__":
    IteratorPatternDemo.main()

运行结果:

bash 复制代码
> python.exe .\iterator_pattern.py                     
============================================================
迭代器模式演示
============================================================

1. 创建名称存储库并添加名称:
----------------------------------------
已添加名称:
  - Robert
  - John
  - Julie
  - Lora

2. 使用迭代器遍历名称:
----------------------------------------
正向遍历:
  1. Robert
  2. John
  3. Julie
  4. Lora

3. 演示多个迭代器独立工作:
----------------------------------------
迭代器1遍历前两个:
  1. Robert
  2. John

迭代器2遍历全部:
  1. Robert
  2. John
  3. Julie
  4. Lora

迭代器1继续遍历剩余:
  3. Julie
  4. Lora

4. 与 Python 内置迭代器对比:
----------------------------------------
自定义迭代器:
  Robert
  John
  Julie
  Lora

Python 列表迭代:
  Robert
  John
  Julie
  Lora

============================================================
迭代器模式的优势:
============================================================
1. 支持以不同的方式遍历聚合对象
2. 迭代器简化了聚合接口
3. 在同一个聚合上可以有多个遍历
4. 迭代器模式分离了集合和遍历逻辑

在本例中:
- Iterator 是迭代器接口(has_next, next)
- Container 是容器接口(get_iterator)
- NamesRepository 是具体容器,存储名称
- NameIterator 是具体迭代器,实现遍历逻辑
- 客户端通过迭代器访问集合,无需知道内部结构
============================================================

4.5. 中介者模式(Mediator)

  • 概要

中介者模式是一种行为型设计模式,它用于将多个对象之间的交互解耦,从而使得对象之间的通信更加简单和灵活。

实现思路:

在中介者模式中,多个对象之间不直接相互通信,而是通过一个中介者对象进行通信。

这样,每个对象只需要和中介者对象通信,而不需要知道其他对象的存在。

中介者对象负责协调各个对象之间的交互,使得系统更加灵活和易于维护。

角色:

Mediator(抽象中介者):定义了各个同事对象之间交互的接口,它通常包含一个或多个抽象方法,用于定义各种交互操作。

ConcreteMediator(具体中介者):实现了抽象中介者接口,负责协调各个同事对象之间的交互关系。

Colleague(抽象同事类):定义了各个同事对象的接口,包含一个指向中介者对象的引用,以便与中介者进行通信。

ConcreteColleague(具体同事类):实现了抽象同事类的接口,负责实现各自的行为,并且需要和中介者对象进行通信。

优点:

解耦了各个对象之间的交互关系,使得系统更加灵活和易于维护。

降低了系统的复杂度,使得各个对象之间的交互变得简单明了。

可以集中管理各个对象之间的交互关系,从而提高系统的可维护性和可扩展性。
缺点:

由于中介者对象需要负责协调各个同事对象之间的交互关系,因此它的职责可能会变得非常复杂。另外,由于中介者对象需要了解各个同事对象之间的交互关系,因此它可能会变得比较庞大。

  • 实现

我们通过聊天室实例来演示中介者模式。实例中,多个用户可以向聊天室发送消息,聊天室向所有的用户显示消息。我们将创建两个类 ChatRoom 和 User。User 对象使用 ChatRoom 方法来分享他们的消息。

MediatorPatternDemo,我们的演示类使用 User 对象来显示他们之间的通信。

python 复制代码
"""
中介者模式 (Mediator Pattern)

定义一个中介对象来封装一系列对象之间的交互。
中介者使各对象不需要显式地相互引用,从而使其耦合松散。
本例中:聊天室作为中介者,协调用户之间的消息传递。
"""

from abc import ABC, abstractmethod
from typing import List
from datetime import datetime


# ============ 中介者接口 ============

class ChatMediator(ABC):
    """
    聊天中介者接口
    
    定义同事对象之间通信的接口
    """
    
    @abstractmethod
    def send_message(self, message: str, user: 'User') -> None:
        """
        发送消息
        
        Args:
            message: 消息内容
            user: 发送消息的用户
        """
        pass
    
    @abstractmethod
    def add_user(self, user: 'User') -> None:
        """
        添加用户
        
        Args:
            user: 要添加的用户
        """
        pass


# ============ 具体中介者 ============

class ChatRoom(ChatMediator):
    """
    聊天室(具体中介者)
    
    协调用户之间的消息传递
    """
    
    def __init__(self, name: str):
        """
        初始化聊天室
        
        Args:
            name: 聊天室名称
        """
        self.name = name
        self.users: List[User] = []
    
    def add_user(self, user: 'User') -> None:
        """
        添加用户到聊天室
        
        Args:
            user: 要添加的用户
        """
        self.users.append(user)
        print(f"[系统] {user.name} 加入了聊天室 '{self.name}'")
    
    def send_message(self, message: str, user: 'User') -> None:
        """
        发送消息给所有其他用户
        
        Args:
            message: 消息内容
            user: 发送者
        """
        timestamp = datetime.now().strftime("%H:%M:%S")
        
        # 广播消息给所有用户(除了发送者)
        for u in self.users:
            if u != user:
                u.receive_message(message, user.name, timestamp)


# ============ 同事类 ============

class User:
    """
    用户类(同事类)
    
    通过中介者(聊天室)与其他用户通信
    """
    
    def __init__(self, name: str, mediator: ChatMediator):
        """
        初始化用户
        
        Args:
            name: 用户名
            mediator: 聊天中介者
        """
        self.name = name
        self.mediator = mediator
    
    def send_message(self, message: str) -> None:
        """
        发送消息
        
        通过中介者发送消息,而不是直接发送给其他用户
        
        Args:
            message: 消息内容
        """
        print(f"[{self.name}] 发送消息: {message}")
        self.mediator.send_message(message, self)
    
    def receive_message(self, message: str, sender_name: str, timestamp: str) -> None:
        """
        接收消息
        
        Args:
            message: 消息内容
            sender_name: 发送者名称
            timestamp: 时间戳
        """
        print(f"[{self.name} 收到消息 {timestamp}] {sender_name}: {message}")


# ============ 演示类 ============

class MediatorPatternDemo:
    """中介者模式演示类"""
    
    @staticmethod
    def main():
        """主方法 - 演示中介者模式的使用"""
        print("=" * 60)
        print("中介者模式演示 - 聊天室")
        print("=" * 60)
        
        # 创建聊天室(中介者)
        print("\n1. 创建聊天室:")
        print("-" * 40)
        chat_room = ChatRoom("Python设计模式学习群")
        print(f"聊天室 '{chat_room.name}' 创建成功!")
        
        # 创建用户并加入聊天室
        print("\n2. 用户加入聊天室:")
        print("-" * 40)
        
        user1 = User("张三", chat_room)
        user2 = User("李四", chat_room)
        user3 = User("王五", chat_room)
        user4 = User("赵六", chat_room)
        
        chat_room.add_user(user1)
        chat_room.add_user(user2)
        chat_room.add_user(user3)
        chat_room.add_user(user4)
        
        # 用户发送消息
        print("\n3. 用户发送消息:")
        print("-" * 40)
        
        user1.send_message("大家好!")
        print()
        
        user2.send_message("你好张三,欢迎来到聊天室!")
        print()
        
        user3.send_message("大家在讨论什么?")
        print()
        
        user4.send_message("我们在学习设计模式。")
        print()
        
        user1.send_message("太好了,我也在学习设计模式!")
        
        # 对比:没有中介者的情况
        print("\n4. 没有中介者的情况(复杂网状结构):")
        print("-" * 40)
        print("如果没有聊天室中介者:")
        print("  张三需要知道李四、王五、赵六的引用")
        print("  李四需要知道张三、王五、赵六的引用")
        print("  ...")
        print("  每个用户都要维护其他所有用户的引用")
        print("  复杂度: O(n^2)")
        print("\n有了中介者(聊天室):")
        print("  每个用户只需要知道聊天室的引用")
        print("  聊天室负责消息转发")
        print("  复杂度: O(n)")
        
        # 总结
        print("\n" + "=" * 60)
        print("中介者模式的优势:")
        print("=" * 60)
        print("1. 减少类之间的耦合")
        print("2. 集中控制交互")
        print("3. 简化对象协议")
        print("4. 符合迪米特法则(最少知识原则)")
        print("\n在本例中:")
        print("- ChatMediator 是中介者接口")
        print("- ChatRoom 是具体中介者,协调用户通信")
        print("- User 是同事类,通过中介者发送/接收消息")
        print("- 用户之间不直接通信,都通过聊天室转发")
        print("- 新增用户只需添加到聊天室,无需修改其他用户")
        print("=" * 60)


if __name__ == "__main__":
    MediatorPatternDemo.main()

运行结果:

bash 复制代码
> python.exe .\mediator_pattern.py
============================================================
中介者模式演示 - 聊天室
============================================================

1. 创建聊天室:
----------------------------------------
聊天室 'Python设计模式学习群' 创建成功!

2. 用户加入聊天室:
----------------------------------------
[系统] 张三 加入了聊天室 'Python设计模式学习群'
[系统] 李四 加入了聊天室 'Python设计模式学习群'
[系统] 王五 加入了聊天室 'Python设计模式学习群'
[系统] 赵六 加入了聊天室 'Python设计模式学习群'

3. 用户发送消息:
----------------------------------------
[张三] 发送消息: 大家好!
[李四 收到消息 15:52:26] 张三: 大家好!
[王五 收到消息 15:52:26] 张三: 大家好!
[赵六 收到消息 15:52:26] 张三: 大家好!

[李四] 发送消息: 你好张三,欢迎来到聊天室!
[张三 收到消息 15:52:26] 李四: 你好张三,欢迎来到聊天室!
[王五 收到消息 15:52:26] 李四: 你好张三,欢迎来到聊天室!
[赵六 收到消息 15:52:26] 李四: 你好张三,欢迎来到聊天室!

[王五] 发送消息: 大家在讨论什么?
[张三 收到消息 15:52:26] 王五: 大家在讨论什么?
[李四 收到消息 15:52:26] 王五: 大家在讨论什么?
[赵六 收到消息 15:52:26] 王五: 大家在讨论什么?

[赵六] 发送消息: 我们在学习设计模式。
[张三 收到消息 15:52:26] 赵六: 我们在学习设计模式。
[李四 收到消息 15:52:26] 赵六: 我们在学习设计模式。
[王五 收到消息 15:52:26] 赵六: 我们在学习设计模式。

[张三] 发送消息: 太好了,我也在学习设计模式!
[李四 收到消息 15:52:26] 张三: 太好了,我也在学习设计模式!
[王五 收到消息 15:52:26] 张三: 太好了,我也在学习设计模式!
[赵六 收到消息 15:52:26] 张三: 太好了,我也在学习设计模式!

4. 没有中介者的情况(复杂网状结构):
----------------------------------------
如果没有聊天室中介者:
  张三需要知道李四、王五、赵六的引用
  李四需要知道张三、王五、赵六的引用
  ...
  每个用户都要维护其他所有用户的引用
  复杂度: O(n^2)

有了中介者(聊天室):
  每个用户只需要知道聊天室的引用
  聊天室负责消息转发
  复杂度: O(n)

============================================================
中介者模式的优势:
============================================================
1. 减少类之间的耦合
2. 集中控制交互
3. 简化对象协议
4. 符合迪米特法则(最少知识原则)

在本例中:
- ChatMediator 是中介者接口
- ChatRoom 是具体中介者,协调用户通信
- User 是同事类,通过中介者发送/接收消息
- 用户之间不直接通信,都通过聊天室转发
- 新增用户只需添加到聊天室,无需修改其他用户
============================================================

4.6. 备忘录模式(Memento)

  • 概要

备忘录模式是一种行为型设计模式,它允许在不暴露对象实现细节的情况下保存和恢复对象的内部状态。

备忘录模式的核心是备忘录类,它用于存储对象的状态信息,同时提供给其他类访问状态信息的接口。

角色:

Originator(发起人):它是需要保存状态的对象。它创建备忘录对象来存储内部状态,并可以使用备忘录对象来恢复其先前的状态。

Memento(备忘录):它是存储发起人对象内部状态的对象。备忘录对象由发起人创建,并由发起人决定何时读取备忘录以恢复其先前的状态。

Caretaker(管理者):它负责备忘录的安全保管。它只能将备忘录传递给其他对象,不能修改备忘录的内容。

在 Python 中,备忘录模式通常使用 Python 的内置 copy 模块和dict属性来实现。

  • 实现

备忘录模式使用三个类 Memento、Originator 和 CareTaker。

Memento 包含了要被恢复的对象的状态。

Originator 创建并在 Memento 对象中存储状态。

Caretaker 对象负责从 Memento 中恢复对象的状态。

MementoPatternDemo,我们的演示类使用 CareTaker 和 Originator 对象来显示对象的状态恢复。

python 复制代码
"""
备忘录模式 (Memento Pattern)

在不破坏封装性的前提下,捕获一个对象的内部状态,
并在该对象之外保存这个状态,以便以后可以将对象恢复到原先保存的状态。
"""

from typing import List


# ============ 备忘录类 ============

class Memento:
    """
    备忘录类
    
    存储发起者的状态
    """
    
    def __init__(self, state: str):
        """
        初始化备忘录
        
        Args:
            state: 要保存的状态
        """
        self._state = state
    
    def get_state(self) -> str:
        """
        获取状态
        
        Returns:
            str: 保存的状态
        """
        return self._state


# ============ 发起人类 ============

class Originator:
    """
    发起人类
    
    创建备忘录并在需要时从备忘录恢复状态
    """
    
    def __init__(self):
        """初始化发起者"""
        self._state = ""
    
    def set_state(self, state: str) -> None:
        """
        设置状态
        
        Args:
            state: 新状态
        """
        print(f"Originator: 设置状态为 '{state}'")
        self._state = state
    
    def get_state(self) -> str:
        """
        获取当前状态
        
        Returns:
            str: 当前状态
        """
        return self._state
    
    def save_state_to_memento(self) -> Memento:
        """
        保存状态到备忘录
        
        Returns:
            Memento: 包含当前状态的备忘录
        """
        print(f"Originator: 保存状态 '{self._state}' 到备忘录")
        return Memento(self._state)
    
    def restore_state_from_memento(self, memento: Memento) -> None:
        """
        从备忘录恢复状态
        
        Args:
            memento: 包含要恢复状态的备忘录
        """
        self._state = memento.get_state()
        print(f"Originator: 从备忘录恢复状态 '{self._state}'")


# ============ 管理者类 ============

class CareTaker:
    """
    管理者类
    
    负责保存备忘录,但不修改备忘录内容
    """
    
    def __init__(self):
        """初始化管理者"""
        self.memento_list: List[Memento] = []
    
    def add(self, memento: Memento) -> None:
        """
        添加备忘录
        
        Args:
            memento: 要保存的备忘录
        """
        self.memento_list.append(memento)
        print(f"CareTaker: 保存备忘录,当前共有 {len(self.memento_list)} 个状态")
    
    def get(self, index: int) -> Memento:
        """
        获取指定索引的备忘录
        
        Args:
            index: 索引
            
        Returns:
            Memento: 备忘录对象
            
        Raises:
            IndexError: 索引越界
        """
        if 0 <= index < len(self.memento_list):
            return self.memento_list[index]
        raise IndexError(f"索引 {index} 超出范围")
    
    def get_last(self) -> Memento:
        """
        获取最后一个备忘录
        
        Returns:
            Memento: 最后一个备忘录
            
        Raises:
            IndexError: 列表为空
        """
        if not self.memento_list:
            raise IndexError("没有保存的备忘录")
        return self.memento_list[-1]
    
    def get_history_count(self) -> int:
        """
        获取历史记录数量
        
        Returns:
            int: 备忘录数量
        """
        return len(self.memento_list)


# ============ 演示类 ============

class MementoPatternDemo:
    """备忘录模式演示类"""
    
    @staticmethod
    def main():
        """主方法 - 演示备忘录模式的使用"""
        print("=" * 60)
        print("备忘录模式演示")
        print("=" * 60)
        
        # 创建发起者和管理者
        print("\n1. 创建 Originator 和 CareTaker:")
        print("-" * 40)
        originator = Originator()
        care_taker = CareTaker()
        
        # 设置并保存状态 #1
        print("\n2. 设置状态 #1 并保存:")
        print("-" * 40)
        originator.set_state("State #1")
        care_taker.add(originator.save_state_to_memento())
        
        # 设置并保存状态 #2
        print("\n3. 设置状态 #2 并保存:")
        print("-" * 40)
        originator.set_state("State #2")
        care_taker.add(originator.save_state_to_memento())
        
        # 设置并保存状态 #3
        print("\n4. 设置状态 #3 并保存:")
        print("-" * 40)
        originator.set_state("State #3")
        care_taker.add(originator.save_state_to_memento())
        
        # 显示当前状态
        print("\n5. 显示当前状态:")
        print("-" * 40)
        print(f"当前状态: {originator.get_state()}")
        
        # 恢复到状态 #2
        print("\n6. 恢复到状态 #2:")
        print("-" * 40)
        originator.restore_state_from_memento(care_taker.get(1))
        print(f"当前状态: {originator.get_state()}")
        
        # 恢复到状态 #1
        print("\n7. 恢复到状态 #1:")
        print("-" * 40)
        originator.restore_state_from_memento(care_taker.get(0))
        print(f"当前状态: {originator.get_state()}")
        
        # 恢复到状态 #3
        print("\n8. 再次恢复到状态 #3:")
        print("-" * 40)
        originator.restore_state_from_memento(care_taker.get(2))
        print(f"当前状态: {originator.get_state()}")
        
        # 显示所有保存的状态
        print("\n9. 所有保存的状态:")
        print("-" * 40)
        for i in range(care_taker.get_history_count()):
            print(f"  状态 #{i + 1}: {care_taker.get(i).get_state()}")
        
        # 总结
        print("\n" + "=" * 60)
        print("备忘录模式的优势:")
        print("=" * 60)
        print("1. 保持封装边界 - 不破坏对象的封装性")
        print("2. 简化 Originator - 状态管理由 CareTaker 负责")
        print("3. 支持撤销/重做功能")
        print("4. 支持历史记录和快照功能")
        print("\n在本例中:")
        print("- Memento 存储状态,对外只读")
        print("- Originator 创建和恢复备忘录")
        print("- CareTaker 管理备忘录集合,不修改内容")
        print("- 可以随时恢复到任意历史状态")
        print("=" * 60)


if __name__ == "__main__":
    MementoPatternDemo.main()

运行结果:

bash 复制代码
> python.exe .\memento_pattern.py                      
============================================================
备忘录模式演示
============================================================

1. 创建 Originator 和 CareTaker:
----------------------------------------

2. 设置状态 #1 并保存:
----------------------------------------
Originator: 设置状态为 'State #1'
Originator: 保存状态 'State #1' 到备忘录
CareTaker: 保存备忘录,当前共有 1 个状态

3. 设置状态 #2 并保存:
----------------------------------------
Originator: 设置状态为 'State #2'
Originator: 保存状态 'State #2' 到备忘录
CareTaker: 保存备忘录,当前共有 2 个状态

4. 设置状态 #3 并保存:
----------------------------------------
Originator: 设置状态为 'State #3'
Originator: 保存状态 'State #3' 到备忘录
CareTaker: 保存备忘录,当前共有 3 个状态

5. 显示当前状态:
----------------------------------------
当前状态: State #3

6. 恢复到状态 #2:
----------------------------------------
Originator: 从备忘录恢复状态 'State #2'
当前状态: State #2

7. 恢复到状态 #1:
----------------------------------------
Originator: 从备忘录恢复状态 'State #1'
当前状态: State #1

8. 再次恢复到状态 #3:
----------------------------------------
Originator: 从备忘录恢复状态 'State #3'
当前状态: State #3

9. 所有保存的状态:
----------------------------------------
  状态 #1: State #1
  状态 #2: State #2
  状态 #3: State #3

============================================================
备忘录模式的优势:
============================================================
1. 保持封装边界 - 不破坏对象的封装性
2. 简化 Originator - 状态管理由 CareTaker 负责
3. 支持撤销/重做功能
4. 支持历史记录和快照功能

在本例中:
- Memento 存储状态,对外只读
- Originator 创建和恢复备忘录
- CareTaker 管理备忘录集合,不修改内容
- 可以随时恢复到任意历史状态
============================================================

4.7. 观察者模式(Observer)

  • 概要

观察者模式是一种软件设计模式,它定义了对象之间的一种一对多的依赖关系,使得当一个对象的状态发生改变时,所有依赖它的对象都会收到通知并自动更新。

这个模式也被称为发布/订阅模式(Publish/Subscribe),事件模型(Event Model)或消息机制(Message Pattern)。

实现思路:

在观察者模式中,有两种类型的对象:观察者和主题(Subject)。

主题是被观察的对象,它维护了一个观察者列表,用于记录所有依赖于它的观察者。

当主题状态发生变化时,它会自动通知所有观察者,让它们能够及时更新自己的状态。

观察者是依赖于主题的对象,当主题状态发生变化时,它们会收到通知并根据新状态更新自己的状态。

优点:

观察者模式的优点是它实现了松耦合(loose coupling)的设计,因为主题和观察者之间没有直接的依赖关系。这使得程序更加灵活,能够更容易地扩展和修改。观察者模式也使得对象能够以可预测的方式进行通信,因为主题和观察者都遵循了同一种接口。同时,观察者模式也可以提高程序的可维护性,因为它将功能分散到了不同的对象中,使得每个对象都具有清晰的职责。
缺点:

它可能会导致过多的细节传递,因为主题在通知观察者时必须传递详细信息。这可能会导致性能问题或安全问题,因为观察者可以访问到主题的私有信息。同时,观察者模式也可能导致循环依赖的问题,因为主题和观察者之间可能会相互依赖。

  • 实现

观察者模式使用三个类 Subject、Observer 和 Client。

Subject 对象带有绑定观察者到 Client 对象和从 Client 对象解绑观察者的方法。

我们创建 Subject 类、Observer 抽象类和扩展了抽象类 Observer 的实体类。

ObserverPatternDemo,我们的演示类使用 Subject 和实体类对象来演示观察者模式。

python 复制代码
"""
观察者模式 (Observer Pattern)

定义对象间的一对多依赖关系,当一个对象状态改变时,
所有依赖于它的对象都会收到通知并自动更新。
"""

from abc import ABC, abstractmethod
from typing import List


# ============ 观察者抽象类 ============

class Observer(ABC):
    """
    观察者抽象类
    
    为所有具体观察者定义更新接口
    """
    
    @abstractmethod
    def update(self, message: str) -> None:
        """
        更新方法
        
        当 Subject 状态改变时被调用
        
        Args:
            message: 更新消息
        """
        pass


# ============ 具体观察者 ============

class BinaryObserver(Observer):
    """二进制观察者"""
    
    def __init__(self, subject: 'Subject'):
        """
        初始化观察者
        
        Args:
            subject: 观察的主题
        """
        self.subject = subject
        self.subject.attach(self)
    
    def update(self, message: str) -> None:
        """
        接收更新通知
        
        Args:
            message: 更新消息
        """
        print(f"BinaryObserver: 收到更新 - {message}")


class OctalObserver(Observer):
    """八进制观察者"""
    
    def __init__(self, subject: 'Subject'):
        """
        初始化观察者
        
        Args:
            subject: 观察的主题
        """
        self.subject = subject
        self.subject.attach(self)
    
    def update(self, message: str) -> None:
        """
        接收更新通知
        
        Args:
            message: 更新消息
        """
        print(f"OctalObserver: 收到更新 - {message}")


class HexObserver(Observer):
    """十六进制观察者"""
    
    def __init__(self, subject: 'Subject'):
        """
        初始化观察者
        
        Args:
            subject: 观察的主题
        """
        self.subject = subject
        self.subject.attach(self)
    
    def update(self, message: str) -> None:
        """
        接收更新通知
        
        Args:
            message: 更新消息
        """
        print(f"HexObserver: 收到更新 - {message}")


# ============ 主题类 ============

class Subject:
    """
    主题类
    
    管理观察者列表,提供添加、删除和通知观察者的方法
    """
    
    def __init__(self):
        """初始化主题"""
        self._observers: List[Observer] = []
        self._state: int = 0
    
    def get_state(self) -> int:
        """
        获取当前状态
        
        Returns:
            int: 当前状态值
        """
        return self._state
    
    def set_state(self, state: int) -> None:
        """
        设置状态并通知所有观察者
        
        Args:
            state: 新状态值
        """
        self._state = state
        print(f"\nSubject: 状态改变为 {state}")
        self.notify_all_observers()
    
    def attach(self, observer: Observer) -> None:
        """
        添加观察者
        
        Args:
            observer: 要添加的观察者
        """
        self._observers.append(observer)
        print(f"Subject: 添加观察者,当前共 {len(self._observers)} 个观察者")
    
    def detach(self, observer: Observer) -> None:
        """
        移除观察者
        
        Args:
            observer: 要移除的观察者
        """
        self._observers.remove(observer)
        print(f"Subject: 移除观察者,当前共 {len(self._observers)} 个观察者")
    
    def notify_all_observers(self) -> None:
        """通知所有观察者"""
        message = f"状态已更新为 {self._state}"
        for observer in self._observers:
            observer.update(message)


# ============ 演示类 ============

class ObserverPatternDemo:
    """观察者模式演示类"""
    
    @staticmethod
    def main():
        """主方法 - 演示观察者模式的使用"""
        print("=" * 60)
        print("观察者模式演示")
        print("=" * 60)
        
        # 创建主题
        print("\n1. 创建主题:")
        print("-" * 40)
        subject = Subject()
        
        # 创建观察者并自动注册
        print("\n2. 创建观察者并注册到主题:")
        print("-" * 40)
        
        hex_observer = HexObserver(subject)
        octal_observer = OctalObserver(subject)
        binary_observer = BinaryObserver(subject)
        
        # 改变主题状态,观察者们会收到通知
        print("\n3. 改变主题状态(观察者收到通知):")
        print("-" * 40)
        
        print("\n第一次状态改变:")
        subject.set_state(15)
        
        print("\n第二次状态改变:")
        subject.set_state(10)
        
        # 移除一个观察者
        print("\n4. 移除 HexObserver:")
        print("-" * 40)
        subject.detach(hex_observer)
        
        # 再次改变状态
        print("\n5. 再次改变状态(HexObserver 不再收到通知):")
        print("-" * 40)
        subject.set_state(20)
        
        # 重新添加观察者
        print("\n6. 重新添加 HexObserver:")
        print("-" * 40)
        subject.attach(hex_observer)
        
        # 再次改变状态
        print("\n7. 再次改变状态(所有观察者都收到通知):")
        print("-" * 40)
        subject.set_state(30)
        
        # 总结
        print("\n" + "=" * 60)
        print("观察者模式的优势:")
        print("=" * 60)
        print("1. 松耦合 - Subject 和 Observer 可以独立变化")
        print("2. 支持广播通信 - 一个 Subject 可以通知多个 Observer")
        print("3. 符合开闭原则 - 可以添加新的 Observer 而不修改 Subject")
        print("4. 建立一套触发机制")
        print("\n在本例中:")
        print("- Subject 是被观察的主题,管理 Observer 列表")
        print("- Observer 是观察者抽象类,定义更新接口")
        print("- HexObserver/OctalObserver/BinaryObserver 是具体观察者")
        print("- 当 Subject 状态改变时,所有注册的 Observer 自动收到通知")
        print("=" * 60)


if __name__ == "__main__":
    ObserverPatternDemo.main()

运行结果:

bash 复制代码
> python.exe .\observer_pattern.py
============================================================
观察者模式演示
============================================================

1. 创建主题:
----------------------------------------

2. 创建观察者并注册到主题:
----------------------------------------
Subject: 添加观察者,当前共 1 个观察者
Subject: 添加观察者,当前共 2 个观察者
Subject: 添加观察者,当前共 3 个观察者

3. 改变主题状态(观察者收到通知):
----------------------------------------

第一次状态改变:

Subject: 状态改变为 15
HexObserver: 收到更新 - 状态已更新为 15
OctalObserver: 收到更新 - 状态已更新为 15
BinaryObserver: 收到更新 - 状态已更新为 15

第二次状态改变:

Subject: 状态改变为 10
HexObserver: 收到更新 - 状态已更新为 10
OctalObserver: 收到更新 - 状态已更新为 10
BinaryObserver: 收到更新 - 状态已更新为 10

4. 移除 HexObserver:
----------------------------------------
Subject: 移除观察者,当前共 2 个观察者

5. 再次改变状态(HexObserver 不再收到通知):
----------------------------------------

Subject: 状态改变为 20
OctalObserver: 收到更新 - 状态已更新为 20
BinaryObserver: 收到更新 - 状态已更新为 20

6. 重新添加 HexObserver:
----------------------------------------
Subject: 添加观察者,当前共 3 个观察者

7. 再次改变状态(所有观察者都收到通知):
----------------------------------------

Subject: 状态改变为 30
OctalObserver: 收到更新 - 状态已更新为 30
BinaryObserver: 收到更新 - 状态已更新为 30
HexObserver: 收到更新 - 状态已更新为 30

============================================================
观察者模式的优势:
============================================================
1. 松耦合 - Subject 和 Observer 可以独立变化
2. 支持广播通信 - 一个 Subject 可以通知多个 Observer
3. 符合开闭原则 - 可以添加新的 Observer 而不修改 Subject
4. 建立一套触发机制

在本例中:
- Subject 是被观察的主题,管理 Observer 列表
- Observer 是观察者抽象类,定义更新接口
- HexObserver/OctalObserver/BinaryObserver 是具体观察者
- 当 Subject 状态改变时,所有注册的 Observer 自动收到通知
============================================================

4.8. 状态模式(State)

  • 概要

状态模式(State)是一种行为型设计模式,它允许对象在不同的内部状态下改变其行为。在状态模式中,一个对象可以有多个状态,每个状态都对应着一组不同的行为。对象根据自身的状态,选择不同的行为。这种模式将状态抽象成独立的类,使得状态之间可以相互切换,而不影响对象的整体行为。

组件:

Context(环境):表示当前对象的状态,它维护一个对抽象状态类的引用,以便能够切换状态。

State(抽象状态):定义一个接口,用于封装与环境相关的行为。

ConcreteState(具体状态):实现抽象状态接口,实现与环境相关的行为。

在状态模式中,当对象的状态发生变化时,它会将状态的处理委托给当前状态对象。状态对象会负责处理相关的操作,并且在必要时会将环境的状态切换到新的状态。

优点:

将状态转换的逻辑封装在状态类中,使得状态之间的切换变得简单明了。

增加新的状态非常容易,只需要增加新的状态类即可。

可以消除大量的条件分支语句,使得代码更加清晰和易于维护。
缺点:

由于需要创建多个状态类,因此会增加系统的复杂度。另外,状态之间的转换也需要仔细设计,否则可能会导致系统的不稳定性。

  • 实现

我们将创建一个 State 接口和实现了 State 接口的实体状态类。Context 是一个带有某个状态的类。

StatePatternDemo,我们的演示类使用 Context 和状态对象来演示 Context 在状态改变时的行为变化。

python 复制代码
"""
状态模式 (State Pattern)

允许对象在内部状态改变时改变它的行为,
对象看起来好像修改了它的类。
"""

from abc import ABC, abstractmethod


# ============ 状态接口 ============

class State(ABC):
    """
    状态接口
    
    定义所有具体状态的公共接口
    """
    
    @abstractmethod
    def do_action(self, context: 'Context') -> None:
        """
        执行动作
        
        Args:
            context: 上下文对象
        """
        pass
    
    @abstractmethod
    def __str__(self) -> str:
        """
        返回状态名称
        
        Returns:
            str: 状态名称
        """
        pass


# ============ 具体状态类 ============

class StartState(State):
    """开始状态"""
    
    def do_action(self, context: 'Context') -> None:
        """
        开始状态下的动作
        
        Args:
            context: 上下文对象
        """
        print("当前处于开始状态,执行开始操作")
        print("  - 初始化资源")
        print("  - 启动服务")
        print("  - 准备就绪")
        
        # 状态转换:从 StartState 转换到 StopState
        print("\n状态转换: StartState -> StopState")
        context.set_state(StopState())
    
    def __str__(self) -> str:
        return "Start State"


class StopState(State):
    """停止状态"""
    
    def do_action(self, context: 'Context') -> None:
        """
        停止状态下的动作
        
        Args:
            context: 上下文对象
        """
        print("当前处于停止状态,执行停止操作")
        print("  - 保存数据")
        print("  - 释放资源")
        print("  - 停止服务")
        
        # 状态转换:从 StopState 转换到 StartState
        print("\n状态转换: StopState -> StartState")
        context.set_state(StartState())
    
    def __str__(self) -> str:
        return "Stop State"


class PauseState(State):
    """暂停状态"""
    
    def do_action(self, context: 'Context') -> None:
        """
        暂停状态下的动作
        
        Args:
            context: 上下文对象
        """
        print("当前处于暂停状态,执行暂停操作")
        print("  - 暂停当前任务")
        print("  - 保存当前进度")
        print("  - 等待恢复")
        
        # 状态转换:从 PauseState 转换到 StartState
        print("\n状态转换: PauseState -> StartState")
        context.set_state(StartState())
    
    def __str__(self) -> str:
        return "Pause State"


# ============ 上下文类 ============

class Context:
    """
    上下文类
    
    维护一个具体状态的实例,这个实例定义当前状态
    """
    
    def __init__(self):
        """初始化上下文,默认状态为 StartState"""
        self._state: State = None
    
    def set_state(self, state: State) -> None:
        """
        设置当前状态
        
        Args:
            state: 新状态
        """
        self._state = state
        print(f"Context: 状态已设置为 [{state}]")
    
    def get_state(self) -> State:
        """
        获取当前状态
        
        Returns:
            State: 当前状态
        """
        return self._state
    
    def do_action(self) -> None:
        """
        执行动作
        
        委托给当前状态对象处理
        """
        if self._state:
            self._state.do_action(self)
        else:
            print("错误: 未设置状态")


# ============ 演示类 ============

class StatePatternDemo:
    """状态模式演示类"""
    
    @staticmethod
    def main():
        """主方法 - 演示状态模式的使用"""
        print("=" * 60)
        print("状态模式演示")
        print("=" * 60)
        
        # 创建上下文
        print("\n1. 创建上下文并设置初始状态:")
        print("-" * 40)
        context = Context()
        context.set_state(StartState())
        
        # 执行动作,观察状态变化和自动转换
        print("\n2. 执行动作(观察状态变化):")
        print("-" * 40)
        
        print("\n第 1 次执行:")
        context.do_action()
        
        print("\n第 2 次执行:")
        context.do_action()
        
        print("\n第 3 次执行:")
        context.do_action()
        
        # 手动切换状态
        print("\n3. 手动切换到暂停状态:")
        print("-" * 40)
        context.set_state(PauseState())
        
        print("\n第 4 次执行:")
        context.do_action()
        
        # 显示当前状态
        print("\n4. 显示当前状态:")
        print("-" * 40)
        print(f"当前状态: {context.get_state()}")
        
        # 演示不同状态下的行为差异
        print("\n5. 演示不同状态下的行为差异:")
        print("-" * 40)
        
        # 创建两个上下文,设置不同状态
        context1 = Context()
        context1.set_state(StartState())
        
        context2 = Context()
        context2.set_state(StopState())
        
        print("\nContext1 (StartState) 执行:")
        context1.do_action()
        
        print("\nContext2 (StopState) 执行:")
        context2.do_action()
        
        # 总结
        print("\n" + "=" * 60)
        print("状态模式的优势:")
        print("=" * 60)
        print("1. 封装转换规则 - 状态转换逻辑集中在状态类中")
        print("2. 消除庞大的条件语句 - 避免使用 if-else 或 switch")
        print("3. 易于扩展 - 添加新状态只需创建新类")
        print("4. 状态行为局部化 - 每个状态的行为在各自类中")
        print("\n在本例中:")
        print("- State 是状态接口,定义 do_action 方法")
        print("- StartState/StopState/PauseState 是具体状态类")
        print("- Context 是上下文,维护当前状态并委托行为")
        print("- 状态转换可以在具体状态中完成")
        print("- 不同状态下,相同的 do_action 调用产生不同行为")
        print("=" * 60)


if __name__ == "__main__":
    StatePatternDemo.main()

运行结果:

bash 复制代码
> python.exe .\state_pattern.py
============================================================
状态模式演示
============================================================

1. 创建上下文并设置初始状态:
----------------------------------------
Context: 状态已设置为 [Start State]

2. 执行动作(观察状态变化):
----------------------------------------

第 1 次执行:
当前处于开始状态,执行开始操作
  - 初始化资源
  - 启动服务
  - 准备就绪

状态转换: StartState -> StopState
Context: 状态已设置为 [Stop State]

第 2 次执行:
当前处于停止状态,执行停止操作
  - 保存数据
  - 释放资源
  - 停止服务

状态转换: StopState -> StartState
Context: 状态已设置为 [Start State]

第 3 次执行:
当前处于开始状态,执行开始操作
  - 初始化资源
  - 启动服务
  - 准备就绪

状态转换: StartState -> StopState
Context: 状态已设置为 [Stop State]

3. 手动切换到暂停状态:
----------------------------------------
Context: 状态已设置为 [Pause State]

第 4 次执行:
当前处于暂停状态,执行暂停操作
  - 暂停当前任务
  - 保存当前进度
  - 等待恢复

状态转换: PauseState -> StartState
Context: 状态已设置为 [Start State]

4. 显示当前状态:
----------------------------------------
当前状态: Start State

5. 演示不同状态下的行为差异:
----------------------------------------
Context: 状态已设置为 [Start State]
Context: 状态已设置为 [Stop State]

Context1 (StartState) 执行:
当前处于开始状态,执行开始操作
  - 初始化资源
  - 启动服务
  - 准备就绪

状态转换: StartState -> StopState
Context: 状态已设置为 [Stop State]

Context2 (StopState) 执行:
当前处于停止状态,执行停止操作
  - 保存数据
  - 释放资源
  - 停止服务

状态转换: StopState -> StartState
Context: 状态已设置为 [Start State]

============================================================
状态模式的优势:
============================================================
1. 封装转换规则 - 状态转换逻辑集中在状态类中
2. 消除庞大的条件语句 - 避免使用 if-else 或 switch
3. 易于扩展 - 添加新状态只需创建新类
4. 状态行为局部化 - 每个状态的行为在各自类中

在本例中:
- State 是状态接口,定义 do_action 方法
- StartState/StopState/PauseState 是具体状态类
- Context 是上下文,维护当前状态并委托行为
- 状态转换可以在具体状态中完成
- 不同状态下,相同的 do_action 调用产生不同行为
============================================================

4.9. 策略模式(Strategy)

  • 概要

策略模式是一种行为型设计模式,它允许在运行时选择算法的不同实现方式。该模式的基本思想是将算法封装在可互换的策略对象中,使得客户端能够动态地选择算法的实现方式。

实现思路:

在策略模式中,通常有一个上下文对象(Context),它持有一个或多个策略对象(Strategy),并将具体的任务委托给其中的某个策略对象来完成。

策略对象之间通常是相互独立的,它们之间没有共享状态,客户端可以自由地选择不同的策略对象。

优点:

可以提高代码的可维护性和可扩展性,因为它将算法的实现与上下文对象分离,使得修改或增加新的算法实现变得更加容易。
缺点:

是可能会增加类的数量,同时需要客户端显式地选择不同的策略对象,这可能会使代码变得更加复杂。

  • 实现

我们将创建一个定义活动的 Strategy 接口和实现了 Strategy 接口的实体策略类。Context 是一个使用了某种策略的类。

StrategyPatternDemo,我们的演示类使用 Context 和策略对象来演示 Context 在它所配置或使用的策略改变时的行为变化。

python 复制代码
"""
策略模式 (Strategy Pattern)

定义一系列算法,把它们一个个封装起来,并且使它们可以互相替换。
策略模式让算法的变化独立于使用算法的客户。
"""

from abc import ABC, abstractmethod
from typing import List


# ============ 策略接口 ============

class Strategy(ABC):
    """
    策略接口
    
    定义所有具体策略的公共接口
    """
    
    @abstractmethod
    def do_operation(self, num1: float, num2: float) -> float:
        """
        执行策略操作
        
        Args:
            num1: 第一个数字
            num2: 第二个数字
            
        Returns:
            float: 操作结果
        """
        pass


# ============ 具体策略类 ============

class OperationAdd(Strategy):
    """加法策略"""
    
    def do_operation(self, num1: float, num2: float) -> float:
        """
        执行加法操作
        
        Args:
            num1: 第一个数字
            num2: 第二个数字
            
        Returns:
            float: 两数之和
        """
        return num1 + num2


class OperationSubtract(Strategy):
    """减法策略"""
    
    def do_operation(self, num1: float, num2: float) -> float:
        """
        执行减法操作
        
        Args:
            num1: 第一个数字
            num2: 第二个数字
            
        Returns:
            float: 两数之差
        """
        return num1 - num2


class OperationMultiply(Strategy):
    """乘法策略"""
    
    def do_operation(self, num1: float, num2: float) -> float:
        """
        执行乘法操作
        
        Args:
            num1: 第一个数字
            num2: 第二个数字
            
        Returns:
            float: 两数之积
        """
        return num1 * num2


class OperationDivide(Strategy):
    """除法策略"""
    
    def do_operation(self, num1: float, num2: float) -> float:
        """
        执行除法操作
        
        Args:
            num1: 第一个数字
            num2: 第二个数字
            
        Returns:
            float: 两数之商
            
        Raises:
            ValueError: 当除数为0时
        """
        if num2 == 0:
            raise ValueError("除数不能为0")
        return num1 / num2


# ============ 上下文类 ============

class Context:
    """
    上下文类
    
    使用策略的类,可以根据需要切换策略
    """
    
    def __init__(self, strategy: Strategy):
        """
        初始化上下文
        
        Args:
            strategy: 初始策略
        """
        self._strategy = strategy
    
    def set_strategy(self, strategy: Strategy) -> None:
        """
        设置策略
        
        Args:
            strategy: 新策略
        """
        self._strategy = strategy
        print(f"Context: 策略已切换为 {strategy.__class__.__name__}")
    
    def get_strategy(self) -> Strategy:
        """
        获取当前策略
        
        Returns:
            Strategy: 当前策略
        """
        return self._strategy
    
    def execute_strategy(self, num1: float, num2: float) -> float:
        """
        执行当前策略
        
        Args:
            num1: 第一个数字
            num2: 第二个数字
            
        Returns:
            float: 执行结果
        """
        return self._strategy.do_operation(num1, num2)


# ============ 演示类 ============

class StrategyPatternDemo:
    """策略模式演示类"""
    
    @staticmethod
    def main():
        """主方法 - 演示策略模式的使用"""
        print("=" * 60)
        print("策略模式演示")
        print("=" * 60)
        
        # 创建上下文,初始使用加法策略
        print("\n1. 创建上下文,初始策略为加法:")
        print("-" * 40)
        context = Context(OperationAdd())
        
        # 执行加法
        num1 = 10
        num2 = 5
        print(f"\n执行: {num1} + {num2}")
        result = context.execute_strategy(num1, num2)
        print(f"结果: {result}")
        
        # 切换到减法策略
        print("\n2. 切换到减法策略:")
        print("-" * 40)
        context.set_strategy(OperationSubtract())
        print(f"\n执行: {num1} - {num2}")
        result = context.execute_strategy(num1, num2)
        print(f"结果: {result}")
        
        # 切换到乘法策略
        print("\n3. 切换到乘法策略:")
        print("-" * 40)
        context.set_strategy(OperationMultiply())
        print(f"\n执行: {num1} * {num2}")
        result = context.execute_strategy(num1, num2)
        print(f"结果: {result}")
        
        # 切换到除法策略
        print("\n4. 切换到除法策略:")
        print("-" * 40)
        context.set_strategy(OperationDivide())
        print(f"\n执行: {num1} / {num2}")
        result = context.execute_strategy(num1, num2)
        print(f"结果: {result}")
        
        # 演示策略的动态切换
        print("\n5. 动态策略切换示例:")
        print("-" * 40)
        
        strategies = [
            OperationAdd(),
            OperationSubtract(),
            OperationMultiply(),
            OperationDivide()
        ]
        
        operations = ['+', '-', '*', '/']
        
        for i, (strategy, op) in enumerate(zip(strategies, operations)):
            context.set_strategy(strategy)
            result = context.execute_strategy(num1, num2)
            print(f"  {num1} {op} {num2} = {result}")
        
        # 对比:不使用策略模式
        print("\n6. 对比 - 不使用策略模式:")
        print("-" * 40)
        print("如果不使用策略模式,需要在 Context 中使用 if-else:")
        print("  if operation == 'add':")
        print("      return num1 + num2")
        print("  elif operation == 'subtract':")
        print("      return num1 - num2")
        print("  ...")
        print("\n添加新算法时需要修改 Context 类,违反开闭原则")
        
        # 总结
        print("\n" + "=" * 60)
        print("策略模式的优势:")
        print("=" * 60)
        print("1. 算法独立变化 - 可以在运行时切换算法")
        print("2. 消除条件语句 - 避免使用 if-else 或 switch")
        print("3. 易于扩展 - 添加新算法只需创建新策略类")
        print("4. 符合开闭原则 - 对扩展开放,对修改关闭")
        print("\n在本例中:")
        print("- Strategy 是策略接口,定义 do_operation 方法")
        print("- OperationAdd/OperationSubtract 等是具体策略")
        print("- Context 是上下文,持有策略引用并执行策略")
        print("- 可以随时切换策略,改变 Context 的行为")
        print("- 新增算法不需要修改 Context 类")
        print("=" * 60)


if __name__ == "__main__":
    StrategyPatternDemo.main()

运行结果:

bash 复制代码
> python.exe .\strategy_pattern.py
============================================================
策略模式演示
============================================================

1. 创建上下文,初始策略为加法:
----------------------------------------

执行: 10 + 5
结果: 15

2. 切换到减法策略:
----------------------------------------
Context: 策略已切换为 OperationSubtract

执行: 10 - 5
结果: 5

3. 切换到乘法策略:
----------------------------------------
Context: 策略已切换为 OperationMultiply

执行: 10 * 5
结果: 50

4. 切换到除法策略:
----------------------------------------
Context: 策略已切换为 OperationDivide

执行: 10 / 5
结果: 2.0

5. 动态策略切换示例:
----------------------------------------
Context: 策略已切换为 OperationAdd
  10 + 5 = 15
Context: 策略已切换为 OperationSubtract
  10 - 5 = 5
Context: 策略已切换为 OperationMultiply
  10 * 5 = 50
Context: 策略已切换为 OperationDivide
  10 / 5 = 2.0

6. 对比 - 不使用策略模式:
----------------------------------------
如果不使用策略模式,需要在 Context 中使用 if-else:
  if operation == 'add':
      return num1 + num2
  elif operation == 'subtract':
      return num1 - num2
  ...

添加新算法时需要修改 Context 类,违反开闭原则

============================================================
策略模式的优势:
============================================================
1. 算法独立变化 - 可以在运行时切换算法
2. 消除条件语句 - 避免使用 if-else 或 switch
3. 易于扩展 - 添加新算法只需创建新策略类
4. 符合开闭原则 - 对扩展开放,对修改关闭

在本例中:
- Strategy 是策略接口,定义 do_operation 方法
- OperationAdd/OperationSubtract 等是具体策略
- Context 是上下文,持有策略引用并执行策略
- 可以随时切换策略,改变 Context 的行为
- 新增算法不需要修改 Context 类
============================================================

4.10. 模板方法模式(TemplateMethod)

  • 概要

模板方法模式是一种行为设计模式,它定义了一个算法的骨架,而将某些步骤的实现延迟到子类中。该模式主要用于在不改变算法结构的情况下重定义算法的某些步骤,以适应不同的需求。

模板方法模式由抽象类和具体子类组成。抽象类定义了一个算法的骨架,它包含若干个抽象方法和具体方法,其中抽象方法表示子类需要实现的步骤,具体方法则提供了默认实现。子类通过继承抽象类并实现其中的抽象方法来完成算法的实现。

优点:

提高代码的复用性:模板方法将算法的核心部分封装在抽象类中,可以使多个子类共享相同的算法实现,避免重复编写相同的代码。

提高代码的扩展性:通过将算法中的一部分步骤交由子类来实现,可以使算法更容易扩展和修改,使得系统更具灵活性和可维护性。

符合开闭原则:模板方法模式通过将变化的部分延迟到子类中来实现算法的扩展和修改,同时保持算法的整体结构不变,符合开闭原则。
缺点:

抽象类和具体子类之间的耦合度较高,一旦抽象类发生修改,所有的子类都需要进行相应的修改。

可能会导致代码的复杂性增加,特别是在存在多个变化的步骤时,需要设计好抽象类和具体子类之间的交互关系,避免出现代码混乱和难以维护的情况。

  • 实现

我们将创建一个定义操作的 Game 抽象类,其中,模板方法设置为 final,这样它就不会被重写。Cricket 和 Football 是扩展了 Game 的实体类,它们重写了抽象类的方法。

TemplatePatternDemo,我们的演示类使用 Game 来演示模板模式的用法。

python 复制代码
"""
模板方法模式 (Template Method Pattern)

定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。
模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。
"""

from abc import ABC, abstractmethod


# ============ 抽象类 ============

class Game(ABC):
    """
    游戏抽象类
    
    定义模板方法和抽象方法
    """
    
    def play(self) -> None:
        """
        模板方法 - 定义游戏的基本流程
        
        该方法定义了算法的骨架,子类不能重写(在Python中通过约定实现)
        """
        print(f"\n开始游戏: {self.__class__.__name__}")
        print("-" * 40)
        
        self.initialize()
        self.start_play()
        self.end_play()
        
        print("-" * 40)
        print(f"游戏结束: {self.__class__.__name__}\n")
    
    @abstractmethod
    def initialize(self) -> None:
        """初始化游戏 - 子类必须实现"""
        pass
    
    @abstractmethod
    def start_play(self) -> None:
        """开始游戏 - 子类必须实现"""
        pass
    
    @abstractmethod
    def end_play(self) -> None:
        """结束游戏 - 子类必须实现"""
        pass


# ============ 具体类 ============

class Cricket(Game):
    """板球游戏"""
    
    def initialize(self) -> None:
        """初始化板球游戏"""
        print("Cricket Game: 初始化中...")
        print("  - 准备板球场地")
        print("  - 设置球板和球")
        print("  - 组建队伍")
    
    def start_play(self) -> None:
        """开始板球游戏"""
        print("Cricket Game: 游戏开始!")
        print("  - 投球手投球")
        print("  - 击球手击球")
        print("  - 跑垒得分")
    
    def end_play(self) -> None:
        """结束板球游戏"""
        print("Cricket Game: 游戏结束!")
        print("  - 计算总分")
        print("  - 宣布获胜者")


class Football(Game):
    """足球游戏"""
    
    def initialize(self) -> None:
        """初始化足球游戏"""
        print("Football Game: 初始化中...")
        print("  - 准备足球场地")
        print("  - 设置球门")
        print("  - 组建队伍")
    
    def start_play(self) -> None:
        """开始足球游戏"""
        print("Football Game: 游戏开始!")
        print("  - 开球")
        print("  - 传球和射门")
        print("  - 防守和进攻")
    
    def end_play(self) -> None:
        """结束足球游戏"""
        print("Football Game: 游戏结束!")
        print("  - 计算比分")
        print("  - 宣布获胜者")


class Basketball(Game):
    """篮球游戏"""
    
    def initialize(self) -> None:
        """初始化篮球游戏"""
        print("Basketball Game: 初始化中...")
        print("  - 准备篮球场地")
        print("  - 设置篮筐")
        print("  - 组建队伍")
    
    def start_play(self) -> None:
        """开始篮球游戏"""
        print("Basketball Game: 游戏开始!")
        print("  - 跳球")
        print("  - 运球和传球")
        print("  - 投篮得分")
    
    def end_play(self) -> None:
        """结束篮球游戏"""
        print("Basketball Game: 游戏结束!")
        print("  - 计算总分")
        print("  - 宣布获胜者")


# ============ 演示类 ============

class TemplatePatternDemo:
    """模板方法模式演示类"""
    
    @staticmethod
    def main():
        """主方法 - 演示模板方法模式的使用"""
        print("=" * 60)
        print("模板方法模式演示")
        print("=" * 60)
        
        # 创建游戏对象
        print("\n1. 创建游戏对象:")
        print("-" * 40)
        
        cricket = Cricket()
        football = Football()
        basketball = Basketball()
        
        # 使用模板方法玩游戏
        print("\n2. 使用模板方法玩板球:")
        cricket.play()
        
        print("\n3. 使用模板方法玩足球:")
        football.play()
        
        print("\n4. 使用模板方法玩篮球:")
        basketball.play()
        
        # 对比:不使用模板方法
        print("\n5. 对比 - 不使用模板方法:")
        print("-" * 40)
        print("如果不使用模板方法,每个游戏类都需要实现完整的流程:")
        print("  class Cricket:")
        print("      def play(self):")
        print("          self.initialize()")
        print("          self.start_play()")
        print("          self.end_play()")
        print("")
        print("  class Football:")
        print("      def play(self):")
        print("          self.initialize()")
        print("          self.start_play()")
        print("          self.end_play()")
        print("")
        print("代码重复!")
        
        # 总结
        print("\n" + "=" * 60)
        print("模板方法模式的优势:")
        print("=" * 60)
        print("1. 代码复用 - 公共流程在父类中实现")
        print("2. 扩展性 - 子类只需实现特定步骤")
        print("3. 算法骨架固定 - 子类不能改变算法结构")
        print("4. 钩子方法 - 可以在父类中添加可选步骤")
        print("\n在本例中:")
        print("- Game 是抽象类,定义模板方法 play()")
        print("- play() 定义了游戏的基本流程: 初始化 -> 开始 -> 结束")
        print("- initialize()/start_play()/end_play() 是抽象方法")
        print("- Cricket/Football/Basketball 是具体类,实现抽象方法")
        print("- 所有游戏共享相同的流程,但具体实现不同")
        print("=" * 60)


if __name__ == "__main__":
    TemplatePatternDemo.main()

运行结果:

bash 复制代码
> python.exe .\template_pattern.py                     
============================================================
模板方法模式演示
============================================================

1. 创建游戏对象:
----------------------------------------

2. 使用模板方法玩板球:

开始游戏: Cricket
----------------------------------------
Cricket Game: 初始化中...
  - 准备板球场地
  - 设置球板和球
  - 组建队伍
Cricket Game: 游戏开始!
  - 投球手投球
  - 击球手击球
  - 跑垒得分
Cricket Game: 游戏结束!
  - 计算总分
  - 宣布获胜者
----------------------------------------
游戏结束: Cricket


3. 使用模板方法玩足球:

开始游戏: Football
----------------------------------------
Football Game: 初始化中...
  - 准备足球场地
  - 设置球门
  - 组建队伍
Football Game: 游戏开始!
  - 开球
  - 传球和射门
  - 防守和进攻
Football Game: 游戏结束!
  - 计算比分
  - 宣布获胜者
----------------------------------------
游戏结束: Football


4. 使用模板方法玩篮球:

开始游戏: Basketball
----------------------------------------
Basketball Game: 初始化中...
  - 准备篮球场地
  - 设置篮筐
  - 组建队伍
Basketball Game: 游戏开始!
  - 跳球
  - 运球和传球
  - 投篮得分
Basketball Game: 游戏结束!
  - 计算总分
  - 宣布获胜者
----------------------------------------
游戏结束: Basketball


5. 对比 - 不使用模板方法:
----------------------------------------
如果不使用模板方法,每个游戏类都需要实现完整的流程:
  class Cricket:
      def play(self):
          self.initialize()
          self.start_play()
          self.end_play()

  class Football:
      def play(self):
          self.initialize()
          self.start_play()
          self.end_play()

代码重复!

============================================================
模板方法模式的优势:
============================================================
1. 代码复用 - 公共流程在父类中实现
2. 扩展性 - 子类只需实现特定步骤
3. 算法骨架固定 - 子类不能改变算法结构
4. 钩子方法 - 可以在父类中添加可选步骤

在本例中:
- Game 是抽象类,定义模板方法 play()
- play() 定义了游戏的基本流程: 初始化 -> 开始 -> 结束
- initialize()/start_play()/end_play() 是抽象方法
- Cricket/Football/Basketball 是具体类,实现抽象方法
- 所有游戏共享相同的流程,但具体实现不同
============================================================

4.11. 访问者模式(Visitor)

  • 概要

访问者模式(Visitor)是一种行为型设计模式,它可以将算法与其所作用的对象分离开来。这种模式允许你在不改变现有对象结构的情况下向对象结构中添加新的行为。

实现思路:

访问者模式的核心思想是:将算法封装到访问者对象中,然后将访问者对象传递给对象结构中的元素,以便这些元素可以调用访问者对象中的算法。

访问者对象可以通过访问元素中的数据和操作来实现算法,从而避免了对元素结构的直接访问。

角色:

访问者(Visitor):定义了用于访问元素的方法,这些方法通常以不同的重载形式出现,以便针对不同类型的元素采取不同的行为。

具体访问者(ConcreteVisitor):实现了访问者接口,提供了算法的具体实现。

元素(Element):定义了用于接受访问者的方法,这些方法通常以 accept() 的形式出现,以便元素可以将自己作为参数传递给访问者对象。

具体元素(ConcreteElement):实现了元素接口,提供了具体的数据和操作,同时也提供了接受访问者的方法。

对象结构(Object Structure):定义了元素的集合,可以提供一些方法以便访问者能够遍历整个集合。

优点:

可以将算法与其所作用的对象分离开来,避免了对元素结构的直接访问。

在访问者中可以实现对元素数据和操作的访问和处理,从而可以方便地扩展新的操作和处理逻辑。

可以方便地实现元素结构的复杂算法,而不需要修改元素结构本身。
缺点:

它可能会导致访问者对象的复杂性增加。此外,它也可能会导致元素结构的扩展性变得比较差,因为每当添加一个新的元素类型时,都需要修改所有的访问者对象。

  • 实现

我们将创建一个定义接受操作的 ComputerPart 接口。Keyboard、Mouse、Monitor 和 Computer 是实现了 ComputerPart 接口的实体类。我们将定义另一个接口 ComputerPartVisitor,它定义了访问者类的操作。Computer 使用实体访问者来执行相应的动作。

VisitorPatternDemo,我们的演示类使用 Computer、ComputerPartVisitor 类来演示访问者模式的用法。

python 复制代码
"""
访问者模式 (Visitor Pattern)

表示一个作用于某对象结构中的各元素的操作,
它使我们可以在不改变各元素的类的前提下定义作用于这些元素的新操作。
"""

from abc import ABC, abstractmethod
from typing import List


# ============ 元素接口 ============

class ComputerPart(ABC):
    """
    计算机部件接口(元素接口)
    
    定义接受访问者的方法
    """
    
    @abstractmethod
    def accept(self, visitor: 'ComputerPartVisitor') -> None:
        """
        接受访问者
        
        Args:
            visitor: 访问者对象
        """
        pass


# ============ 具体元素类 ============

class Keyboard(ComputerPart):
    """键盘"""
    
    def accept(self, visitor: 'ComputerPartVisitor') -> None:
        """接受访问者访问"""
        visitor.visit_keyboard(self)
    
    def type(self) -> str:
        """获取键盘类型"""
        return "标准键盘"


class Mouse(ComputerPart):
    """鼠标"""
    
    def accept(self, visitor: 'ComputerPartVisitor') -> None:
        """接受访问者访问"""
        visitor.visit_mouse(self)
    
    def type(self) -> str:
        """获取鼠标类型"""
        return "光电鼠标"


class Monitor(ComputerPart):
    """显示器"""
    
    def accept(self, visitor: 'ComputerPartVisitor') -> None:
        """接受访问者访问"""
        visitor.visit_monitor(self)
    
    def size(self) -> str:
        """获取显示器尺寸"""
        return "27英寸"


class Computer(ComputerPart):
    """
    计算机类(对象结构)
    
    包含多个部件,并负责协调访问者对各个部件的访问
    """
    
    def __init__(self):
        """初始化计算机,包含所有部件"""
        self.parts: List[ComputerPart] = [
            Keyboard(),
            Mouse(),
            Monitor()
        ]
    
    def accept(self, visitor: 'ComputerPartVisitor') -> None:
        """
        接受访问者访问
        
        遍历所有部件,让访问者访问每个部件
        
        Args:
            visitor: 访问者对象
        """
        print(f"\nComputer: 接受 {visitor.__class__.__name__} 访问")
        print("-" * 40)
        
        for part in self.parts:
            part.accept(visitor)
    
    def get_parts(self) -> List[ComputerPart]:
        """获取所有部件"""
        return self.parts


# ============ 访问者接口 ============

class ComputerPartVisitor(ABC):
    """
    计算机部件访问者接口
    
    为每个具体元素定义访问操作
    """
    
    @abstractmethod
    def visit_keyboard(self, keyboard: Keyboard) -> None:
        """访问键盘"""
        pass
    
    @abstractmethod
    def visit_mouse(self, mouse: Mouse) -> None:
        """访问鼠标"""
        pass
    
    @abstractmethod
    def visit_monitor(self, monitor: Monitor) -> None:
        """访问显示器"""
        pass


# ============ 具体访问者类 ============

class ComputerPartDisplayVisitor(ComputerPartVisitor):
    """部件显示访问者 - 显示部件信息"""
    
    def visit_keyboard(self, keyboard: Keyboard) -> None:
        """访问键盘 - 显示信息"""
        print(f"显示: 键盘 [{keyboard.type()}]")
    
    def visit_mouse(self, mouse: Mouse) -> None:
        """访问鼠标 - 显示信息"""
        print(f"显示: 鼠标 [{mouse.type()}]")
    
    def visit_monitor(self, monitor: Monitor) -> None:
        """访问显示器 - 显示信息"""
        print(f"显示: 显示器 [{monitor.size()}]")


class ComputerPartPriceVisitor(ComputerPartVisitor):
    """部件价格访问者 - 计算部件价格"""
    
    def __init__(self):
        """初始化价格计算器"""
        self.total_price = 0
    
    def visit_keyboard(self, keyboard: Keyboard) -> None:
        """访问键盘 - 获取价格"""
        price = 200
        self.total_price += price
        print(f"价格: 键盘 [{keyboard.type()}] = {price}元")
    
    def visit_mouse(self, mouse: Mouse) -> None:
        """访问鼠标 - 获取价格"""
        price = 100
        self.total_price += price
        print(f"价格: 鼠标 [{mouse.type()}] = {price}元")
    
    def visit_monitor(self, monitor: Monitor) -> None:
        """访问显示器 - 获取价格"""
        price = 1500
        self.total_price += price
        print(f"价格: 显示器 [{monitor.size()}] = {price}元")
    
    def get_total_price(self) -> int:
        """获取总价"""
        return self.total_price


class ComputerPartMaintenanceVisitor(ComputerPartVisitor):
    """部件维护访问者 - 检查部件状态"""
    
    def visit_keyboard(self, keyboard: Keyboard) -> None:
        """访问键盘 - 维护检查"""
        print(f"维护: 检查键盘 [{keyboard.type()}] - 按键正常,清洁度良好")
    
    def visit_mouse(self, mouse: Mouse) -> None:
        """访问鼠标 - 维护检查"""
        print(f"维护: 检查鼠标 [{mouse.type()}] - 点击正常,传感器清洁")
    
    def visit_monitor(self, monitor: Monitor) -> None:
        """访问显示器 - 维护检查"""
        print(f"维护: 检查显示器 [{monitor.size()}] - 显示正常,无坏点")


# ============ 演示类 ============

class VisitorPatternDemo:
    """访问者模式演示类"""
    
    @staticmethod
    def main():
        """主方法 - 演示访问者模式的使用"""
        print("=" * 60)
        print("访问者模式演示")
        print("=" * 60)
        
        # 创建计算机
        print("\n1. 创建计算机:")
        print("-" * 40)
        computer = Computer()
        print("计算机包含: 键盘、鼠标、显示器")
        
        # 使用显示访问者
        print("\n2. 使用显示访问者访问计算机:")
        print("-" * 40)
        display_visitor = ComputerPartDisplayVisitor()
        computer.accept(display_visitor)
        
        # 使用价格访问者
        print("\n3. 使用价格访问者计算总价:")
        print("-" * 40)
        price_visitor = ComputerPartPriceVisitor()
        computer.accept(price_visitor)
        print(f"\n总价: {price_visitor.get_total_price()}元")
        
        # 使用维护访问者
        print("\n4. 使用维护访问者检查部件:")
        print("-" * 40)
        maintenance_visitor = ComputerPartMaintenanceVisitor()
        computer.accept(maintenance_visitor)
        
        # 展示添加新操作无需修改部件类
        print("\n5. 优势展示 - 添加新操作:")
        print("-" * 40)
        print("如需添加'部件升级'功能,只需创建新的访问者类:")
        print("  class UpgradeVisitor(ComputerPartVisitor):")
        print("      def visit_keyboard(self, keyboard):")
        print("          print('升级键盘固件')")
        print("      def visit_mouse(self, mouse):")
        print("          print('升级鼠标DPI')")
        print("      def visit_monitor(self, monitor):")
        print("          print('升级显示器驱动')")
        print("\n无需修改 Keyboard、Mouse、Monitor 类!")
        
        # 总结
        print("\n" + "=" * 60)
        print("访问者模式的优势:")
        print("=" * 60)
        print("1. 分离算法与对象结构 - 将操作从元素类中分离")
        print("2. 易于添加新操作 - 只需添加新的访问者类")
        print("3. 符合开闭原则 - 对扩展开放,对修改关闭")
        print("4. 集中相关操作 - 相关操作集中在访问者中")
        print("\n在本例中:")
        print("- ComputerPart 是元素接口,定义 accept 方法")
        print("- Keyboard/Mouse/Monitor/Computer 是具体元素")
        print("- ComputerPartVisitor 是访问者接口")
        print("- DisplayVisitor/PriceVisitor/MaintenanceVisitor 是具体访问者")
        print("- 可以在不修改部件类的情况下添加新操作")
        print("=" * 60)


if __name__ == "__main__":
    VisitorPatternDemo.main()

运行结果:

bash 复制代码
> python.exe .\visitor_pattern.py                      
============================================================
访问者模式演示
============================================================

1. 创建计算机:
----------------------------------------
计算机包含: 键盘、鼠标、显示器

2. 使用显示访问者访问计算机:
----------------------------------------

Computer: 接受 ComputerPartDisplayVisitor 访问
----------------------------------------
显示: 键盘 [标准键盘]
显示: 鼠标 [光电鼠标]
显示: 显示器 [27英寸]

3. 使用价格访问者计算总价:
----------------------------------------

Computer: 接受 ComputerPartPriceVisitor 访问
----------------------------------------
价格: 键盘 [标准键盘] = 200元
价格: 鼠标 [光电鼠标] = 100元
价格: 显示器 [27英寸] = 1500元

总价: 1800元

4. 使用维护访问者检查部件:
----------------------------------------

Computer: 接受 ComputerPartMaintenanceVisitor 访问
----------------------------------------
维护: 检查键盘 [标准键盘] - 按键正常,清洁度良好
维护: 检查鼠标 [光电鼠标] - 点击正常,传感器清洁
维护: 检查显示器 [27英寸] - 显示正常,无坏点

5. 优势展示 - 添加新操作:
----------------------------------------
如需添加'部件升级'功能,只需创建新的访问者类:
  class UpgradeVisitor(ComputerPartVisitor):
      def visit_keyboard(self, keyboard):
          print('升级键盘固件')
      def visit_mouse(self, mouse):
          print('升级鼠标DPI')
      def visit_monitor(self, monitor):
          print('升级显示器驱动')

无需修改 Keyboard、Mouse、Monitor 类!

============================================================
访问者模式的优势:
============================================================
1. 分离算法与对象结构 - 将操作从元素类中分离
2. 易于添加新操作 - 只需添加新的访问者类
3. 符合开闭原则 - 对扩展开放,对修改关闭
4. 集中相关操作 - 相关操作集中在访问者中

在本例中:
- ComputerPart 是元素接口,定义 accept 方法
- Keyboard/Mouse/Monitor/Computer 是具体元素
- ComputerPartVisitor 是访问者接口
- DisplayVisitor/PriceVisitor/MaintenanceVisitor 是具体访问者
- 可以在不修改部件类的情况下添加新操作
============================================================
相关推荐
always_TT2 小时前
从Python_Java转学C语言需要注意什么?
java·c语言·python
2301_793804693 小时前
定时任务专家:Python Schedule库使用指南
jvm·数据库·python
穿越世纪的风尘4 小时前
【问题解决】No module named ‘_sqlite3‘
python·centos
qq_416018724 小时前
用Python批量处理Excel和CSV文件
jvm·数据库·python
云道轩4 小时前
告诉 Claude Code 在项目中遵循特定的编程模式/设计模式和技术栈约束
设计模式·ai·agent·claude code
蓝天守卫者联盟14 小时前
2026乙酸乙酯回收设备厂家选型与技术实践
java·jvm·python·算法
在屏幕前出油5 小时前
06. FastAPI——中间件
后端·python·中间件·pycharm·fastapi
Datacarts5 小时前
亚马逊爆款选品:数据采集与三方服务商对接
开发语言·人工智能·python·信息可视化
IronMurphy5 小时前
Java 泛型深度解析:编译期类型擦除机制与 PECS 准则
java·windows·python