Python 设计模式实践

实验环境:Python 3.12.3 | ECS服务器 ecs-5d9b-0001 (192.168.0.186)
实验时间:2026-07-05
实验内容:8个实验,覆盖创建型、结构型、行为型三大类共14种设计模式

目录


课程概述

设计模式是软件设计中常见问题的可复用解决方案。它们不是可以直接转换为代码的模板,而是解决特定问题的最佳实践。本课程以蓝桥云课功能为案例背景,使用 Python 为实现语言,系统学习14种常见设计模式。

设计模式分为三大类:

分类 关注点 包含模式
创建型模式 对象的创建机制 单例、工厂方法、抽象工厂
结构型模式 类和对象的组合 适配器、装饰器、代理、组合、外观、享元
行为型模式 对象之间的通信 策略、观察者、命令、模板方法

实验1:创建型 - 单例模式

知识点

  1. 设计模式简介
  2. 单例模式的三种实现方式

原理

单例模式(Singleton Pattern)确保一个类只有一个实例,并提供一个全局访问点。

适用场景:数据库连接池、日志管理器、配置管理、缓存系统等。

三种实现方式

  • 模块实现(Python模块天然单例)
  • __new__ 方法实现
  • 装饰器实现

代码实现

# -*- coding: utf-8 -*-
"""
实验1:创建型 - 单例模式
知识点: 1.设计模式简介 2.单例模式的三种实现方式
"""
import sys
import time
import threading

# ============================================================
# 方式一:使用模块实现单例
# ============================================================
# Python 模块在第一次导入时会被加载,之后的导入会直接引用已加载的模块
# 因此模块天然是单例的

class ConfigModule:
    _instance = None
    settings = {
        "db_host": "192.168.0.186",
        "db_port": 3306,
        "debug": True
    }

config_singleton = ConfigModule()

# ============================================================
# 方式二:使用 __new__ 方法实现单例
# ============================================================
class SingletonNew:
    """通过重写 __new__ 方法实现单例(双重检查锁)"""
    _instance = None
    _lock = threading.Lock()

    def __new__(cls, *args, **kwargs):
        if cls._instance is None:
            with cls._lock:
                if cls._instance is None:
                    cls._instance = super().__new__(cls)
                    cls._instance._initialized = False
        return cls._instance

    def __init__(self, value=None):
        if not self._initialized:
            self.value = value
            self._initialized = True
        # 已初始化则跳过

# ============================================================
# 方式三:使用装饰器实现单例
# ============================================================
def singleton(cls):
    """单例装饰器"""
    instances = {}
    lock = threading.Lock()

    def get_instance(*args, **kwargs):
        if cls not in instances:
            with lock:
                if cls not in instances:
                    instances[cls] = cls(*args, **kwargs)
        return instances[cls]

    return get_instance

@singleton
class DatabaseConnection:
    """模拟数据库连接"""
    def __init__(self, host="localhost", port=3306):
        self.host = host
        self.port = port
        self.connected = False
        self.queries = 0

    def connect(self):
        if not self.connected:
            self.connected = True

    def execute(self, sql):
        self.queries += 1
        return f"Result of: {sql}"

@singleton
class Logger:
    def __init__(self):
        self.logs = []

    def log(self, msg):
        timestamp = time.strftime("%H:%M:%S")
        entry = f"[{timestamp}] {msg}"
        self.logs.append(entry)
        return entry

上机输出

======================================================================
实验1:创建型 - 单例模式 (Singleton Pattern)
======================================================================

【设计模式简介】
设计模式是软件设计中常见问题的可复用解决方案。它们不是可以直接转换为
代码的模板,而是解决特定问题的最佳实践。设计模式分为三大类:
  1. 创建型模式 - 关注对象的创建机制
  2. 结构型模式 - 关注类和对象的组合
  3. 行为型模式 - 关注对象之间的通信

单例模式确保一个类只有一个实例,并提供一个全局访问点。
适用场景:数据库连接池、日志管理器、配置管理、缓存系统等。

----------------------------------------------------------------------
方式一:使用模块实现单例
----------------------------------------------------------------------
配置模块初始化: {'db_host': '192.168.0.186', 'db_port': 3306, 'debug': True}
模块在首次导入时创建,后续导入直接引用同一对象,天然实现单例

----------------------------------------------------------------------
方式二:使用 __new__ 方法实现单例
----------------------------------------------------------------------
创建第一个实例:
  [初始化] 创建单例实例, value=first_config
  s1.value = first_config
创建第二个实例:
  [跳过] 实例已存在, value=first_config
  s2.value = first_config

  s1 is s2: True
  id(s1) = 124079354406016
  id(s2) = 124079354406016

----------------------------------------------------------------------
方式三:使用装饰器实现单例
----------------------------------------------------------------------
创建数据库连接实例1:
  [装饰器] 首次创建 DatabaseConnection 实例
  连接到数据库 192.168.0.186:3306
  执行SQL[1]: SELECT * FROM users
  执行SQL[2]: SELECT * FROM orders

创建数据库连接实例2:
  已经连接到 192.168.0.186:3306,无需重复连接
  执行SQL[3]: SELECT * FROM products

  db1 is db2: True
  db1.host = 192.168.0.186, db2.host = 192.168.0.186
  总查询数: 3

----------------------------------------------------------------------
线程安全测试
----------------------------------------------------------------------
  Logger 初始化完成, id=124079354406400
  [装饰器] 首次创建 Logger 实例

  日志总数: 10
    [21:00:22] Thread-0 开始工作
    [21:00:22] Thread-1 开始工作
    [21:00:22] Thread-2 开始工作
    [21:00:22] Thread-3 开始工作
    [21:00:22] Thread-4 开始工作
    [21:00:22] Thread-0 完成工作
    [21:00:22] Thread-1 完成工作
    [21:00:22] Thread-2 完成工作
    [21:00:22] Thread-3 完成工作
    [21:00:22] Thread-4 完成工作

======================================================================
实验1完成!三种单例实现方式均验证通过。
======================================================================

小结

实现方式 线程安全 特点
模块单例 最简单,Python模块天然单例
__new__ 方法 双重检查锁,控制实例化过程
装饰器 最灵活,可复用于任意类

实验2:Python 元类简介与使用

知识点

  1. 元类的概念
  2. 利用 __new__ 方法控制类的属性
  3. 利用 __init__ 方法控制类的属性
  4. 利用 __call__ 方法设置类的调用规则

原理

在 Python 中,一切皆对象。类也是对象,而创建类的类就是「元类」。

  • type 是 Python 内置的元类,所有类最终都由 type 创建
  • 可以通过继承 type 来自定义元类
  • 元类常用于:API 框架(Django ORM)、属性验证、自动注册、接口检查等

类创建流程

class MyClass(metaclass=MyMeta):
    pass
→ Python 调用 MyMeta.__new__ 创建类对象
→ Python 调用 MyMeta.__init__ 初始化类对象
→ 之后每次实例化 MyClass 时,调用 MyMeta.__call__

代码实现

# -*- coding: utf-8 -*-
"""
实验2:Python 元类简介与使用
"""
from abc import ABC, abstractmethod
import time

# 1. type 的基本用法 - 动态创建类
DynamicClass = type("DynamicClass", (object,), {"name": "Dynamic", "greet": lambda self: f"Hello from {self.name}!"})

# 2. 利用 __new__ 方法控制类的属性
class ValidateAttributesMeta(type):
    """在类创建时验证属性名必须全小写"""
    def __new__(mcs, name, bases, namespace, **kwargs):
        for attr_name in namespace:
            if not attr_name.startswith('_') and attr_name != attr_name.lower():
                raise ValueError(f"属性名 '{attr_name}' 必须全小写!")
        namespace['_attr_count'] = len([k for k in namespace if not k.startswith('__')])
        cls = super().__new__(mcs, name, bases, namespace, **kwargs)
        return cls

class UserModel(metaclass=ValidateAttributesMeta):
    username = "admin"
    email = "admin@example.com"
    active = True

# 3. 利用 __init__ 方法控制类的属性
class AutoRegisterMeta(type):
    """自动注册类,并在 __init__ 中添加元信息"""
    _registry = {}

    def __init__(cls, name, bases, namespace, **kwargs):
        super().__init__(name, bases, namespace, **kwargs)
        cls._created_at = time.strftime("%Y-%m-%d %H:%M:%S")
        if name != "BasePlugin":
            AutoRegisterMeta._registry[name] = cls

class BasePlugin(metaclass=AutoRegisterMeta):
    plugin_type = "base"

class DatabasePlugin(BasePlugin):
    plugin_type = "database"

class CachePlugin(BasePlugin):
    plugin_type = "cache"

# 4. 利用 __call__ 方法设置类的调用规则
class SingletonMeta(type):
    """通过 __call__ 实现单例"""
    _instances = {}

    def __call__(cls, *args, **kwargs):
        if cls not in cls._instances:
            cls._instances[cls] = super().__call__(*args, **kwargs)
        return cls._instances[cls]

class AppConfig(metaclass=SingletonMeta):
    def __init__(self):
        self.config = {}

# 5. 综合示例:简易 ORM 元类
class Field:
    def __init__(self, field_type, max_length=None):
        self.field_type = field_type
        self.max_length = max_length
        self.name = None

class CharField(Field):
    def __init__(self, max_length=255):
        super().__init__("VARCHAR", max_length)

class IntegerField(Field):
    def __init__(self):
        super().__init__("INTEGER")

class BooleanField(Field):
    def __init__(self):
        super().__init__("BOOLEAN")

class ORMMeta(type):
    """模拟 Django ORM 的元类,自动收集字段"""
    def __new__(mcs, name, bases, namespace, **kwargs):
        fields = {}
        for key, value in list(namespace.items()):
            if isinstance(value, Field):
                value.name = key
                fields[key] = value
        namespace['_fields'] = fields
        namespace['_table_name'] = name.lower()
        cls = super().__new__(mcs, name, bases, namespace, **kwargs)
        return cls

class Model(metaclass=ORMMeta):
    _fields = {}
    _table_name = ""

    @classmethod
    def create_sql(cls):
        cols = []
        for name, field in cls._fields.items():
            col = f"{name} {field.field_type}"
            if field.max_length:
                col += f"({field.max_length})"
            cols.append(col)
        return f"CREATE TABLE {cls._table_name} ({', '.join(cols)});"

class User(Model):
    id = IntegerField()
    username = CharField(max_length=50)
    email = CharField(max_length=100)
    is_active = BooleanField()

上机输出

======================================================================
实验2:Python 元类简介与使用 (Metaclass)
======================================================================

【元类的概念】
在 Python 中,一切皆对象。类也是对象,而创建类的类就是「元类」。
  - type 是 Python 内置的元类,所有类最终都由 type 创建
  - 可以通过继承 type 来自定义元类
  - 元类常用于:API 框架(Django ORM)、属性验证、自动注册、接口检查等

类创建流程:
  class MyClass(metaclass=MyMeta):
      pass
  → Python 调用 MyMeta.__new__ 创建类对象
  → Python 调用 MyMeta.__init__ 初始化类对象
  → 之后每次实例化 MyClass 时,调用 MyMeta.__call__

----------------------------------------------------------------------
1. type 的基本用法 - 动态创建类
----------------------------------------------------------------------
  动态创建的类: <class '__main__.DynamicClass'>
  type(DynamicClass) = <class 'type'>
  obj.greet() = Hello from Dynamic!

----------------------------------------------------------------------
2. 利用 __new__ 方法控制类的属性
----------------------------------------------------------------------
创建符合规范的类:
  [__new__] 正在创建类: UserModel
  UserModel._attr_count = 3
  UserModel.username = admin

尝试创建不符合规范的类:
  [__new__] 正在创建类: BadModel
  捕获错误: 属性名 'UserName' 必须全小写!

----------------------------------------------------------------------
3. 利用 __init__ 方法控制类的属性
----------------------------------------------------------------------
  [__init__] 初始化类: BasePlugin
  [__init__] 初始化类: DatabasePlugin
  [__init__] 已注册插件: DatabasePlugin -> <class '__main__.DatabasePlugin'>
  [__init__] 初始化类: CachePlugin
  [__init__] 已注册插件: CachePlugin -> <class '__main__.CachePlugin'>
  [__init__] 初始化类: AuthPlugin
  [__init__] 已注册插件: AuthPlugin -> <class '__main__.AuthPlugin'>

  已注册的插件:
    DatabasePlugin: type=database, created_at=2026-07-05 20:54:40
    CachePlugin: type=cache, created_at=2026-07-05 20:54:40
    AuthPlugin: type=auth, created_at=2026-07-05 20:54:40

----------------------------------------------------------------------
4. 利用 __call__ 方法设置类的调用规则
----------------------------------------------------------------------
第一次创建 AppConfig:
  [__call__] 首次实例化 AppConfig
  AppConfig.__init__ 被调用

第二次创建 AppConfig:
  [__call__] 返回已有实例 AppConfig
  app1 is app2: True
  app2.get('env') = production
  app2.get('port') = 9003

----------------------------------------------------------------------
5. 综合示例:简易 ORM 元类
----------------------------------------------------------------------
User 模型:
  表名: user
  字段:
    id: Field(INTEGER)
    username: Field(VARCHAR, max_length=50)
    email: Field(VARCHAR, max_length=100)
    is_active: Field(BOOLEAN)
  SQL: CREATE TABLE user (id INTEGER, username VARCHAR(50), email VARCHAR(100), is_active BOOLEAN);

Product 模型:
  表名: product
  字段:
    id: Field(INTEGER)
    name: Field(VARCHAR, max_length=200)
    price: Field(INTEGER)
    in_stock: Field(BOOLEAN)
  SQL: CREATE TABLE product (id INTEGER, name VARCHAR(200), price INTEGER, in_stock BOOLEAN);

======================================================================
实验2完成!元类的 __new__/__init__/__call__ 三大方法均验证通过。
======================================================================

小结

元类方法 调用时机 典型用途
__new__ 创建类对象时 属性验证、字段收集、修改类结构
__init__ 初始化类对象时 自动注册、添加元信息
__call__ 实例化类时 单例控制、实例缓存

实验3:创建型 - 工厂模式

知识点

  1. 抽象类
  2. 简单工厂模式
  3. 工厂方法模式
  4. 抽象工厂模式

原理

工厂模式是最常用的设计模式之一,用于创建对象时隐藏创建逻辑。

代码实现

# -*- coding: utf-8 -*-
"""
实验3:创建型 - 工厂模式
"""
from abc import ABC, abstractmethod

# 1. 抽象类
class Animal(ABC):
    def __init__(self, name):
        self.name = name

    @abstractmethod
    def speak(self): pass

    @abstractmethod
    def move(self): pass

class Dog(Animal):
    def speak(self): return f"{self.name}: 汪汪汪!"
    def move(self): return f"{self.name} 用四条腿奔跑"

class Cat(Animal):
    def speak(self): return f"{self.name}: 喵喵喵!"
    def move(self): return f"{self.name} 优雅地踱步"

# 2. 简单工厂模式
class AnimalFactory:
    _registry = {"dog": Dog, "cat": Cat, "bird": Bird}

    @staticmethod
    def create(animal_type, name):
        cls = AnimalFactory._registry.get(animal_type.lower())
        if cls is None:
            raise ValueError(f"未知的动物类型: {animal_type}")
        return cls(name)

# 3. 工厂方法模式
class AnimalCreator(ABC):
    @abstractmethod
    def factory_method(self): pass

    def create_and_describe(self, name):
        animal = self.factory_method(name)
        return animal

class DogCreator(AnimalCreator):
    def factory_method(self, name): return Dog(name)

class CatCreator(AnimalCreator):
    def factory_method(self, name): return Cat(name)

# 4. 抽象工厂模式
class Button(ABC):
    @abstractmethod
    def render(self): pass

class Input(ABC):
    @abstractmethod
    def render(self): pass

class WindowsButton(Button):
    def render(self): return "[Windows Button: ▢ Click Me]"

class MacButton(Button):
    def render(self): return "[Mac Button: ◉ Click Me]"

class UIFactory(ABC):
    @abstractmethod
    def create_button(self) -> Button: pass
    @abstractmethod
    def create_input(self) -> Input: pass

class WindowsUIFactory(UIFactory):
    def create_button(self): return WindowsButton()
    def create_input(self): return WindowsInput()

class MacUIFactory(UIFactory):
    def create_button(self): return MacButton()
    def create_input(self): return MacInput()

上机输出

======================================================================
实验3:创建型 - 工厂模式 (Factory Pattern)
======================================================================

工厂模式是最常用的设计模式之一,用于创建对象时隐藏创建逻辑。
分为三种形式:
  1. 简单工厂模式 - 一个工厂类根据参数创建不同对象
  2. 工厂方法模式 - 每个产品有对应的工厂子类
  3. 抽象工厂模式 - 创建一系列相关产品

----------------------------------------------------------------------
1. 抽象类 (Abstract Class)
----------------------------------------------------------------------
  Dog(旺财)
    speak: 旺财: 汪汪汪!
    move:  旺财 用四条腿奔跑
  Cat(咪咪)
    speak: 咪咪: 喵喵喵!
    move:  咪咪 优雅地踱步
  Bird(小翠)
    speak: 小翠: 叽叽喳喳!
    move:  小翠 在天空中飞翔

尝试直接实例化抽象类:
  错误: Can't instantiate abstract class Animal without an implementation for abstract methods 'move', 'speak'

----------------------------------------------------------------------
2. 简单工厂模式 (Simple Factory)
----------------------------------------------------------------------
使用简单工厂创建动物:
  [工厂] 创建 dog -> Dog(大黄)
  [工厂] 创建 cat -> Cat(橘子)
  [工厂] 创建 bird -> Bird(鹦鹉)
  大黄: 汪汪汪!
  橘子: 喵喵喵!
  鹦鹉: 叽叽喳喳!

注册新动物类型:
  [工厂] 注册新类型: fish -> Fish
  [工厂] 创建 fish -> Fish(尼莫)
  尼莫: .... (鱼不会说话)
  尼莫 在水里游动

----------------------------------------------------------------------
3. 工厂方法模式 (Factory Method)
----------------------------------------------------------------------
工厂方法模式:将对象的创建延迟到子类中实现

使用工厂方法模式:
  [工厂方法] DogCreator 创建了 Dog(小Dog)
    -> 小Dog: 汪汪汪!
  [工厂方法] CatCreator 创建了 Cat(小Cat)
    -> 小Cat: 喵喵喵!
  [工厂方法] BirdCreator 创建了 Bird(小Bird)
    -> 小Bird: 叽叽喳喳!

----------------------------------------------------------------------
4. 抽象工厂模式 (Abstract Factory)
----------------------------------------------------------------------
抽象工厂模式:创建一系列相关或相互依赖的对象

使用抽象工厂模式创建不同平台的UI:

  === Windows 平台 UI ===
    按钮: [Windows Button: ▢ Click Me]
    输入框: [Windows Input: ____________]

  === macOS 平台 UI ===
    按钮: [Mac Button: ◉ Click Me]
    输入框: [Mac Input: ¯¯¯¯¯¯¯¯¯¯¯¯¯]

  === Web 平台 UI ===
    按钮: <button>Click Me</button>
    输入框: <input type='text' />

----------------------------------------------------------------------
5. 三种工厂模式对比
----------------------------------------------------------------------

  ┌──────────────┬────────────────────────────┬─────────────────────────────┐
  │ 模式         │ 特点                       │ 适用场景                    │
  ├──────────────┼────────────────────────────┼─────────────────────────────┤
  │ 简单工厂     │ 一个工厂类,switch/if判断  │ 产品少,变化不频繁          │
  │              │ 违反开闭原则               │                             │
  ├──────────────┼────────────────────────────┼─────────────────────────────┤
  │ 工厂方法     │ 每个产品一个工厂子类       │ 产品扩展频繁                │
  │              │ 符合开闭原则               │ 需要灵活扩展                │
  ├──────────────┼────────────────────────────┼─────────────────────────────┤
  │ 抽象工厂     │ 创建一系列相关产品         │ 需要创建产品族              │
  │              │ 产品族一起变化             │ 跨平台/主题切换             │
  └──────────────┴────────────────────────────┴─────────────────────────────┘

======================================================================
实验3完成!简单工厂、工厂方法、抽象工厂三种模式均验证通过。
======================================================================

实验4:结构型 - 适配器模式、装饰器模式

知识点

  1. 适配器模式
  2. 装饰器模式

原理

适配器模式:将一个类的接口转换成客户端期望的另一个接口,使原本接口不兼容的类可以一起工作。生活中的例子包括 USB转Type-C适配器、电压转换器。

装饰器模式:动态地给对象添加额外职责,比继承更灵活,可以在运行时添加/移除功能。

代码实现

# -*- coding: utf-8 -*-
"""
实验4:结构型 - 适配器模式 & 装饰器模式
"""
from abc import ABC, abstractmethod
import functools
import time

# ========== 适配器模式 ==========

# 旧版日志接口
class OldLogger:
    def write_message(self, msg): print(f"  [OldLogger] {msg}")
    def write_error(self, msg): print(f"  [OldLogger][ERROR] {msg}")

# 新版日志接口
class NewLoggerInterface(ABC):
    @abstractmethod
    def log(self, level, message): pass
    @abstractmethod
    def info(self, message): pass
    @abstractmethod
    def error(self, message): pass
    @abstractmethod
    def debug(self, message): pass

# 第三方日志库
class ThirdPartyLogger:
    def __init__(self, name="ThirdParty"):
        self.name = name
    def emit(self, level, msg):
        print(f"  [{self.name}][{level}] {msg}")

# 适配器:将旧版日志适配到新接口
class LoggerAdapter(NewLoggerInterface):
    def __init__(self, old_logger):
        self._logger = old_logger

    def log(self, level, message):
        if level.upper() == "ERROR":
            self._logger.write_error(message)
        else:
            self._logger.write_message(f"[{level}] {message}")

    def info(self, message): self._logger.write_message(f"[INFO] {message}")
    def error(self, message): self._logger.write_error(message)
    def debug(self, message): self._logger.write_message(f"[DEBUG] {message}")

# 适配器:适配第三方日志库
class ThirdPartyAdapter(NewLoggerInterface):
    def __init__(self, third_party):
        self._logger = third_party

    def log(self, level, message): self._logger.emit(level, message)
    def info(self, message): self._logger.emit("INFO", message)
    def error(self, message): self._logger.emit("ERROR", message)
    def debug(self, message): self._logger.emit("DEBUG", message)

# 客户端代码 - 只依赖新接口
def client_code(logger: NewLoggerInterface):
    logger.info("系统启动")
    logger.debug("调试信息")
    logger.error("发生错误")
    logger.log("WARNING", "警告信息")

# ========== 装饰器模式 ==========

class Coffee(ABC):
    @abstractmethod
    def cost(self): pass
    @abstractmethod
    def description(self): pass

class SimpleCoffee(Coffee):
    def cost(self): return 10.0
    def description(self): return "简单咖啡"

class CoffeeDecorator(Coffee):
    def __init__(self, coffee: Coffee):
        self._coffee = coffee
    def cost(self): return self._coffee.cost()
    def description(self): return self._coffee.description()

class MilkDecorator(CoffeeDecorator):
    def cost(self): return self._coffee.cost() + 3.0
    def description(self): return self._coffee.description() + " + 牛奶"

class SugarDecorator(CoffeeDecorator):
    def cost(self): return self._coffee.cost() + 1.0
    def description(self): return self._coffee.description() + " + 糖"

class WhipDecorator(CoffeeDecorator):
    def cost(self): return self._coffee.cost() + 5.0
    def description(self): return self._coffee.description() + " + 奶泡"

class CaramelDecorator(CoffeeDecorator):
    def cost(self): return self._coffee.cost() + 4.0
    def description(self): return self._coffee.description() + " + 焦糖"

# ========== Python 函数装饰器 ==========

def timing(func):
    @functools.wraps(func)
    def wrapper(*args, **kwargs):
        start = time.perf_counter()
        result = func(*args, **kwargs)
        elapsed = time.perf_counter() - start
        print(f"  [计时] {func.__name__} 耗时: {elapsed:.6f}s")
        return result
    return wrapper

def memoize(func):
    cache = {}
    @functools.wraps(func)
    def wrapper(*args):
        if args not in cache:
            cache[args] = func(*args)
        return cache[args]
    return wrapper

@timing
@memoize
def fibonacci(n):
    if n <= 1: return n
    return fibonacci(n - 1) + fibonacci(n - 2)

上机输出

======================================================================
实验4:结构型 - 适配器模式 & 装饰器模式
======================================================================
----------------------------------------------------------------------
1. 适配器模式 (Adapter Pattern)
----------------------------------------------------------------------

适配器模式:将一个类的接口转换成客户端期望的另一个接口。
使原本接口不兼容的类可以一起工作。

生活中的例子:
  - USB转Type-C适配器
  - 电压转换器 (220V -> 5V)
  - 翻译官(两种语言之间的桥梁)

使用旧版日志(通过适配器):
  [OldLogger] [INFO] 系统启动
  [OldLogger] [DEBUG] 调试信息
  [OldLogger][ERROR] 发生错误
  [OldLogger] [WARNING] 警告信息

使用第三方日志(通过适配器):
  [Log4Py][INFO] 系统启动
  [Log4Py][DEBUG] 调试信息
  [Log4Py][ERROR] 发生错误
  [Log4Py][WARNING] 警告信息

----------------------------------------------------------------------
2. 装饰器模式 (Decorator Pattern)
----------------------------------------------------------------------

装饰器模式:动态地给对象添加额外职责。
比继承更灵活,可以在运行时添加/移除功能。

核心思想:装饰器和被装饰者实现同一接口,装饰器内部持有被装饰者的引用

点单咖啡:
  简单咖啡: ¥10.0
  简单咖啡 + 牛奶: ¥13.0
  简单咖啡 + 糖 + 牛奶 + 奶泡: ¥19.0
  简单咖啡 + 牛奶 + 奶泡 + 焦糖: ¥22.0

----------------------------------------------------------------------
3. Python 函数装饰器实践
----------------------------------------------------------------------
计算 fibonacci(10):
  [日志] 调用 fibonacci(10)
  [日志] 调用 fibonacci(9)
  [日志] 调用 fibonacci(8)
  [日志] 调用 fibonacci(7)
  [日志] 调用 fibonacci(6)
  [日志] 调用 fibonacci(5)
  [日志] 调用 fibonacci(4)
  [日志] 调用 fibonacci(3)
  [日志] 调用 fibonacci(2)
  [日志] 调用 fibonacci(1)
  [缓存] fibonacci(1,) 已缓存
  [日志] fibonacci 返回: 1
  [计时] fibonacci 耗时: 0.000006s
  [日志] 调用 fibonacci(0)
  [缓存] fibonacci(0,) 已缓存
  [日志] fibonacci 返回: 0
  [计时] fibonacci 耗时: 0.000005s
  [缓存] fibonacci(2,) 已缓存
  [日志] fibonacci 返回: 1
  [计时] fibonacci 耗时: 0.000020s
  [日志] 调用 fibonacci(1)
  [缓存] fibonacci(1,) 命中缓存
  [日志] fibonacci 返回: 1
  [计时] fibonacci 耗时: 0.000006s
  [缓存] fibonacci(3,) 已缓存
  [日志] fibonacci 返回: 2
  [计时] fibonacci 耗时: 0.000032s
  [日志] 调用 fibonacci(2)
  [缓存] fibonacci(2,) 命中缓存
  [日志] fibonacci 返回: 1
  [计时] fibonacci 耗时: 0.000003s
  [缓存] fibonacci(4,) 已缓存
  [日志] fibonacci 返回: 3
  [计时] fibonacci 耗时: 0.000041s
  [日志] 调用 fibonacci(3)
  [缓存] fibonacci(3,) 命中缓存
  [日志] fibonacci 返回: 2
  [计时] fibonacci 耗时: 0.000003s
  [缓存] fibonacci(5,) 已缓存
  [日志] fibonacci 返回: 5
  [计时] fibonacci 耗时: 0.000049s
  [日志] 调用 fibonacci(4)
  [缓存] fibonacci(4,) 命中缓存
  [日志] fibonacci 返回: 3
  [计时] fibonacci 耗时: 0.000003s
  [缓存] fibonacci(6,) 已缓存
  [日志] fibonacci 返回: 8
  [计时] fibonacci 耗时: 0.000058s
  [日志] 调用 fibonacci(5)
  [缓存] fibonacci(5,) 命中缓存
  [日志] fibonacci 返回: 5
  [计时] fibonacci 耗时: 0.000003s
  [缓存] fibonacci(7,) 已缓存
  [日志] fibonacci 返回: 13
  [计时] fibonacci 耗时: 0.000066s
  [日志] 调用 fibonacci(6)
  [缓存] fibonacci(6,) 命中缓存
  [日志] fibonacci 返回: 8
  [计时] fibonacci 耗时: 0.000003s
  [缓存] fibonacci(8,) 已缓存
  [日志] fibonacci 返回: 21
  [计时] fibonacci 耗时: 0.000075s
  [日志] 调用 fibonacci(7)
  [缓存] fibonacci(7,) 命中缓存
  [日志] fibonacci 返回: 13
  [计时] fibonacci 耗时: 0.000003s
  [缓存] fibonacci(9,) 已缓存
  [日志] fibonacci 返回: 34
  [计时] fibonacci 耗时: 0.000085s
  [日志] 调用 fibonacci(8)
  [缓存] fibonacci(8,) 命中缓存
  [日志] fibonacci 返回: 21
  [计时] fibonacci 耗时: 0.000003s
  [缓存] fibonacci(10,) 已缓存
  [日志] fibonacci 返回: 55
  [计时] fibonacci 耗时: 0.000098s
  结果: fibonacci(10) = 55

再次计算 fibonacci(10) (使用缓存):
  [日志] 调用 fibonacci(10)
  [缓存] fibonacci(10,) 命中缓存
  [日志] fibonacci 返回: 55
  [计时] fibonacci 耗时: 0.000003s
  结果: fibonacci(10) = 55

测试重试装饰器:
  API调用成功

----------------------------------------------------------------------
4. 类装饰器
----------------------------------------------------------------------
  Point: Point(x=3, y=4)
  c1 is c2: True
  c1.increment() = 1
  c2.increment() = 2

======================================================================
实验4完成!适配器模式和装饰器模式均验证通过。
======================================================================

实验5:结构型 - 代理模式、组合模式

知识点

  1. 代理模式
  2. 组合模式

原理

代理模式:为其他对象提供代理以控制对这个对象的访问。包括虚拟代理(延迟加载)、保护代理(权限控制)等。

组合模式:将对象组合成树形结构来表示"部分-整体"的层次结构,使客户端可以统一处理单个对象和组合对象。

代码实现

# -*- coding: utf-8 -*-
"""
实验5:结构型 - 代理模式 & 组合模式
"""
from abc import ABC, abstractmethod
import time

# ========== 代理模式:虚拟代理 ==========

class Image(ABC):
    @abstractmethod
    def display(self): pass
    @abstractmethod
    def get_info(self): pass

class RealImage(Image):
    def __init__(self, filename):
        self._filename = filename
        self._loaded = False
        self._size = 0
        self._load_from_disk()

    def _load_from_disk(self):
        time.sleep(0.3)  # 模拟加载耗时
        self._loaded = True
        self._size = 1024 * 1024 * 5  # 5MB

    def display(self):
        print(f"    [RealImage] 显示图片: {self._filename}")

    def get_info(self):
        return f"文件: {self._filename}, 大小: {self._size // 1024}KB, 已加载: {self._loaded}"

class ProxyImage(Image):
    """虚拟代理:延迟加载图片"""
    def __init__(self, filename):
        self._filename = filename
        self._real_image = None  # 延迟创建

    def display(self):
        if self._real_image is None:
            self._real_image = RealImage(self._filename)
        self._real_image.display()

    def get_info(self):
        if self._real_image is None:
            return f"文件: {self._filename}, 大小: 未知(未加载), 已加载: False"
        return self._real_image.get_info()

# ========== 代理模式:保护代理 ==========

class DataAccessor(ABC):
    @abstractmethod
    def read(self, key): pass
    @abstractmethod
    def write(self, key, value): pass
    @abstractmethod
    def delete(self, key): pass

class RealDataAccessor(DataAccessor):
    def __init__(self):
        self._data = {"user_001": "Alice", "user_002": "Bob", "admin": "Charlie"}
    def read(self, key): return self._data.get(key, "NOT_FOUND")
    def write(self, key, value):
        self._data[key] = value
        return f"写入成功: {key}={value}"
    def delete(self, key):
        if key in self._data:
            del self._data[key]
            return f"删除成功: {key}"
        return f"键不存在: {key}"

class ProtectedDataAccessor(DataAccessor):
    """保护代理:基于角色控制访问"""
    def __init__(self, real_accessor, user_role):
        self._real = real_accessor
        self._role = user_role
        self._permissions = {
            "guest": {"read"},
            "user": {"read", "write"},
            "admin": {"read", "write", "delete"},
        }

    def _check_permission(self, action):
        allowed = self._permissions.get(self._role, set())
        if action not in allowed:
            raise PermissionError(f"权限拒绝: 角色 '{self._role}' 无权执行 '{action}'")

    def read(self, key):
        self._check_permission("read")
        return self._real.read(key)
    def write(self, key, value):
        self._check_permission("write")
        return self._real.write(key, value)
    def delete(self, key):
        self._check_permission("delete")
        return self._real.delete(key)

# ========== 组合模式:文件系统 ==========

class FileSystemComponent(ABC):
    def __init__(self, name):
        self._name = name
    @abstractmethod
    def display(self, indent=0): pass
    @abstractmethod
    def get_size(self): pass

class File(FileSystemComponent):
    def __init__(self, name, size):
        super().__init__(name)
        self._size = size
    def display(self, indent=0):
        prefix = "  " * indent
        print(f"{prefix}📄 {self._name} ({self._size}KB)")
    def get_size(self): return self._size

class Folder(FileSystemComponent):
    def __init__(self, name):
        super().__init__(name)
        self._children = []
    def add(self, component):
        self._children.append(component)
        return self
    def display(self, indent=0):
        prefix = "  " * indent
        print(f"{prefix}📁 {self._name}/ ({self.get_size()}KB)")
        for child in self._children:
            child.display(indent + 1)
    def get_size(self):
        return sum(child.get_size() for child in self._children)

上机输出

======================================================================
实验5:结构型 - 代理模式 & 组合模式
======================================================================
----------------------------------------------------------------------
1. 代理模式 (Proxy Pattern)
----------------------------------------------------------------------

代理模式:为其他对象提供代理以控制对这个对象的访问。

代理类型:
  - 远程代理:为远程对象提供本地代表
  - 虚拟代理:延迟创建开销大的对象(懒加载)
  - 保护代理:控制访问权限
  - 智能引用代理:在访问时附加额外操作

>>> 虚拟代理(延迟加载)
创建代理图片对象(不立即加载):
  代理信息: 文件: landscape_4k.jpg, 大小: 未知(未加载), 已加载: False

调用 display() 触发加载:
    [Proxy] 首次访问,延迟加载图片...
    [RealImage] 正在从磁盘加载: landscape_4k.jpg ...
    [RealImage] 加载完成: landscape_4k.jpg (5120KB)
    [RealImage] 显示图片: landscape_4k.jpg

再次获取信息: 文件: landscape_4k.jpg, 大小: 5120KB, 已加载: True

>>> 保护代理(权限控制)
guest 用户操作:
  read('user_001'): Alice
  write('user_003'): 权限拒绝: 角色 'guest' 无权执行 'write'

admin 用户操作:
  read('admin'): Charlie
  write('user_003', 'Dave'): 写入成功: user_003=Dave
  delete('user_002'): 删除成功: user_002

----------------------------------------------------------------------
2. 组合模式 (Composite Pattern)
----------------------------------------------------------------------

组合模式:将对象组合成树形结构来表示"部分-整体"的层次结构。
使客户端可以统一处理单个对象和组合对象。

适用场景:
  - 文件系统(文件和文件夹)
  - 组织架构(部门和员工)
  - UI组件树(容器和叶子组件)

文件系统结构:
📁 project/ (70KB)
  📁 src/ (26KB)
    📄 main.py (15KB)
    📄 utils.py (8KB)
    📄 config.py (3KB)
  📁 tests/ (9KB)
    📄 test_main.py (5KB)
    📄 test_utils.py (4KB)
  📁 docs/ (32KB)
    📄 README.md (12KB)
    📄 API.md (20KB)
  📄 requirements.txt (1KB)
  📄 setup.py (2KB)

总大小: 70KB
src 目录大小: 26KB
docs 目录大小: 32KB
总文件数: 9

----------------------------------------------------------------------
3. 组合模式 - 组织架构示例
----------------------------------------------------------------------
组织架构:
🏢 蓝桥科技有限公司 (人数:8, 预算:¥231000/月)
  🏢 工程部 (人数:5, 预算:¥146000/月)
    👤 张三 - 工程总监 (¥50000/月)
    👤 李四 - 高级工程师 (¥30000/月)
    👤 王五 - 工程师 (¥20000/月)
    🏢 前端组 (人数:2, 预算:¥46000/月)
      👤 赵六 - 前端负责人 (¥28000/月)
      👤 钱七 - 前端工程师 (¥18000/月)
  🏢 市场部 (人数:2, 预算:¥60000/月)
    👤 孙八 - 市场总监 (¥45000/月)
    👤 周九 - 市场专员 (¥15000/月)
  🏢 人力资源部 (人数:1, 预算:¥25000/月)
    👤 吴十 - HR经理 (¥25000/月)

公司总人数: 8
公司月预算: ¥231000

======================================================================
实验5完成!代理模式和组合模式均验证通过。
======================================================================

实验6:结构型 - 外观模式、享元模式

知识点

  1. 外观模式
  2. 享元模式

原理

外观模式:为子系统中的一组接口提供一个一致的界面,定义一个高层接口使子系统更容易使用。

享元模式:通过共享对象来减少内存使用和提高性能,适用于大量相似对象的场景。核心概念是区分内部状态(可共享)和外部状态(不可共享)。

代码实现

# -*- coding: utf-8 -*-
"""
实验6:结构型 - 外观模式 & 享元模式
"""
from abc import ABC, abstractmethod

# ========== 外观模式 ==========

class CPU:
    def freeze(self): print("    [CPU] 冻结")
    def jump(self, position): print(f"    [CPU] 跳转到地址 {position}")
    def execute(self): print("    [CPU] 执行指令")

class Memory:
    def load(self, address, data):
        print(f"    [Memory] 加载数据到地址 {address}: {data}")

class HardDrive:
    def read(self, lba, size):
        print(f"    [HardDrive] 读取扇区 {lba}, 大小 {size} bytes")
        return f"BOOT_DATA_{lba}"

class PowerSupply:
    def turn_on(self): print("    [PowerSupply] 电源开启")
    def turn_off(self): print("    [PowerSupply] 电源关闭")

class CoolingSystem:
    def start_fan(self, speed=50): print(f"    [Cooling] 风扇启动 (转速: {speed}%)")
    def stop_fan(self): print("    [Cooling] 风扇停止")

class ComputerFacade:
    """电脑外观:一键开机/关机"""
    def __init__(self):
        self.cpu = CPU()
        self.memory = Memory()
        self.hard_drive = HardDrive()
        self.power = PowerSupply()
        self.cooling = CoolingSystem()

    def start(self):
        self.power.turn_on()
        self.cooling.start_fan(80)
        cpu_data = self.hard_drive.read(0x00, 1024)
        self.memory.load(0x00, cpu_data)
        self.cpu.freeze()
        self.cpu.jump(0x00)
        self.cpu.execute()

    def shutdown(self):
        self.cpu.freeze()
        self.cooling.stop_fan()
        self.power.turn_off()

# ========== 享元模式 ==========

class CharacterFlyweight:
    """享元对象:共享字符的字体属性"""
    def __init__(self, char, font, size, color):
        self.char = char      # 内部状态
        self.font = font      # 内部状态
        self.size = size      # 内部状态
        self.color = color    # 内部状态

    def display(self, position):
        """外部状态 position 作为参数传入"""
        print(f"    字符 '{self.char}' | 字体:{self.font} 大小:{self.size} 颜色:{self.color} | 位置:({position[0]}, {position[1]})")

class CharacterFactory:
    """享元工厂:管理共享对象"""
    _flyweights = {}

    @classmethod
    def get_flyweight(cls, char, font, size, color):
        key = (char, font, size, color)
        if key not in cls._flyweights:
            cls._flyweights[key] = CharacterFlyweight(char, font, size, color)
        return cls._flyweights[key]

    @classmethod
    def get_count(cls):
        return len(cls._flyweights)

class GoStoneFlyweight:
    """享元:围棋棋子(只有黑白两种)"""
    def __init__(self, color):
        self.color = color  # 内部状态

    def place(self, x, y):
        """外部状态:坐标"""
        icon = "⚫" if self.color == "black" else "⚪"
        print(f"    {icon} 放置在 ({x}, {y})")

上机输出

======================================================================
实验6:结构型 - 外观模式 & 享元模式
======================================================================
----------------------------------------------------------------------
1. 外观模式 (Facade Pattern)
----------------------------------------------------------------------

外观模式:为子系统中的一组接口提供一个一致的界面。
定义一个高层接口,使子系统更容易使用。

核心思想:简化复杂子系统的使用,客户端只需要和外观交互。

实际应用:
  - 一键启动电脑(CPU、内存、硬盘、显卡协同初始化)
  - 家庭影院一键观看电影(音响、投影、灯光、窗帘协同)
  - 编译系统的 build 命令

使用外观模式启动电脑:
  >>> 电脑开机流程:
    [PowerSupply] 电源开启
    [Cooling] 风扇启动 (转速: 80%)
    [HardDrive] 读取扇区 0, 大小 1024 bytes
    [Memory] 加载数据到地址 0: BOOT_DATA_0
    [CPU] 冻结
    [CPU] 跳转到地址 0
    [CPU] 执行指令
  >>> 开机完成!系统就绪。

使用外观模式关闭电脑:
  >>> 电脑关机流程:
    [CPU] 冻结
    [Cooling] 风扇停止
    [PowerSupply] 电源关闭
  >>> 关机完成。

----------------------------------------------------------------------
  外观模式 - 家庭影院示例
----------------------------------------------------------------------
  >>> 准备看电影:
    [灯光] 调暗到 10%
    [幕布] 降下
    [投影仪] 开启
    [投影仪] 模式: 电影
    [功放] 开启
    [功放] 音量设为 60
  >>> 一切就绪,享受电影!

  >>> 结束观影:
    [功放] 关闭
    [投影仪] 关闭
    [幕布] 升起
    [灯光] 全亮
  >>> 已恢复日常模式。

----------------------------------------------------------------------
2. 享元模式 (Flyweight Pattern)
----------------------------------------------------------------------

享元模式:通过共享对象来减少内存使用和提高性能。
适用于大量相似对象的场景。

核心概念:
  - 内部状态:可以共享的部分(不随环境变化)
  - 外部状态:不能共享的部分(随环境变化)

经典应用:文本编辑器中的字符对象、游戏中的粒子系统、线程池

>>> 文档编辑器示例

编辑 'Hello World' (统一字体):
    [工厂] 创建新享元: 'H' (Arial, 12, black)
    字符 'H' | 字体:Arial 大小:12 颜色:black | 位置:(0, 0)
    [工厂] 创建新享元: 'e' (Arial, 12, black)
    字符 'e' | 字体:Arial 大小:12 颜色:black | 位置:(10, 0)
    [工厂] 创建新享元: 'l' (Arial, 12, black)
    字符 'l' | 字体:Arial 大小:12 颜色:black | 位置:(20, 0)
    [工厂] 复用享元: 'l' (Arial, 12, black)
    字符 'l' | 字体:Arial 大小:12 颜色:black | 位置:(30, 0)
    [工厂] 创建新享元: 'o' (Arial, 12, black)
    字符 'o' | 字体:Arial 大小:12 颜色:black | 位置:(40, 0)
    [工厂] 创建新享元: ' ' (Arial, 12, black)
    字符 ' ' | 字体:Arial 大小:12 颜色:black | 位置:(50, 0)
    [工厂] 创建新享元: 'W' (Arial, 12, black)
    字符 'W' | 字体:Arial 大小:12 颜色:black | 位置:(60, 0)
    [工厂] 复用享元: 'o' (Arial, 12, black)
    字符 'o' | 字体:Arial 大小:12 颜色:black | 位置:(70, 0)
    [工厂] 创建新享元: 'r' (Arial, 12, black)
    字符 'r' | 字体:Arial 大小:12 颜色:black | 位置:(80, 0)
    [工厂] 复用享元: 'l' (Arial, 12, black)
    字符 'l' | 字体:Arial 大小:12 颜色:black | 位置:(90, 0)
    [工厂] 创建新享元: 'd' (Arial, 12, black)
    字符 'd' | 字体:Arial 大小:12 颜色:black | 位置:(100, 0)

  文档共 11 个字符, 实际创建享元对象: 8 个
  节省内存: 3 个对象

编辑混合字体文档:
    [工厂] 创建新享元: 'H' (Arial, 12, black)
    字符 'H' | 字体:Arial 大小:12 颜色:black | 位置:(0, 0)
    [工厂] 创建新享元: 'e' (Arial, 12, black)
    字符 'e' | 字体:Arial 大小:12 颜色:black | 位置:(10, 0)
    [工厂] 创建新享元: 'l' (Arial, 12, black)
    字符 'l' | 字体:Arial 大小:12 颜色:black | 位置:(20, 0)
    [工厂] 复用享元: 'l' (Arial, 12, black)
    字符 'l' | 字体:Arial 大小:12 颜色:black | 位置:(30, 0)
    [工厂] 创建新享元: 'o' (Arial, 12, black)
    字符 'o' | 字体:Arial 大小:12 颜色:black | 位置:(40, 0)
    [工厂] 创建新享元: ' ' (Arial, 12, black)
    字符 ' ' | 字体:Arial 大小:12 颜色:black | 位置:(50, 0)
    [工厂] 创建新享元: 'W' (Times, 14, red)
    字符 'W' | 字体:Times 大小:14 颜色:red | 位置:(60, 0)
    [工厂] 复用享元: 'o' (Arial, 12, black)
    字符 'o' | 字体:Arial 大小:12 颜色:black | 位置:(70, 0)
    [工厂] 创建新享元: 'r' (Times, 14, red)
    字符 'r' | 字体:Times 大小:14 颜色:red | 位置:(80, 0)
    [工厂] 复用享元: 'l' (Arial, 12, black)
    字符 'l' | 字体:Arial 大小:12 颜色:black | 位置:(90, 0)
    [工厂] 创建新享元: 'd' (Arial, 12, black)
    字符 'd' | 字体:Arial 大小:12 颜色:black | 位置:(100, 0)

  混合文档共 11 个字符, 实际创建享元对象: 8 个

>>> 围棋棋子示例
模拟围棋对局:
    [工厂] 创建 black 棋子
    ⚫ 放置在 (3, 3)
    [工厂] 创建 white 棋子
    ⚪ 放置在 (3, 4)
    ⚫ 放置在 (4, 4)
    ⚪ 放置在 (4, 3)
    ⚫ 放置在 (5, 3)
    ⚪ 放置在 (3, 5)
    ⚫ 放置在 (6, 3)
    ⚪ 放置在 (2, 4)
    ⚫ 放置在 (7, 3)
    ⚪ 放置在 (3, 2)
    ⚫ 放置在 (8, 3)
    ⚪ 放置在 (4, 2)

  总落子数: 12
  实际创建棋子对象: 2 (仅黑白2个)
  内存节省: 10 个对象

======================================================================
实验6完成!外观模式和享元模式均验证通过。
======================================================================

实验7:行为型 - 策略模式、观察者模式

知识点

  1. 策略模式
  2. 观察者模式

原理

策略模式:定义一系列算法,将它们封装起来,使它们可以互相替换。使算法的变化独立于使用算法的客户端。

观察者模式:定义对象间的一对多依赖关系,当一个对象状态发生变化时,所有依赖于它的对象都会得到通知并自动更新。又称发布-订阅模式。

代码实现

# -*- coding: utf-8 -*-
"""
实验7:行为型 - 策略模式 & 观察者模式
"""
from abc import ABC, abstractmethod
import time

# ========== 策略模式 ==========

class DiscountStrategy(ABC):
    @abstractmethod
    def calculate(self, price): pass
    @abstractmethod
    def get_name(self): pass

class NoDiscount(DiscountStrategy):
    def calculate(self, price): return price
    def get_name(self): return "无折扣"

class PercentageDiscount(DiscountStrategy):
    def __init__(self, percent): self.percent = percent
    def calculate(self, price): return price * (1 - self.percent / 100)
    def get_name(self): return f"{self.percent}%折扣"

class FullReductionDiscount(DiscountStrategy):
    def __init__(self, threshold, reduction):
        self.threshold = threshold
        self.reduction = reduction
    def calculate(self, price):
        return price - self.reduction if price >= self.threshold else price
    def get_name(self): return f"满{self.threshold}{self.reduction}"

class TieredDiscount(DiscountStrategy):
    def __init__(self, tiers): self.tiers = tiers
    def calculate(self, price):
        applicable_percent = 0
        for threshold, percent in self.tiers:
            if price >= threshold: applicable_percent = percent
        return price * (1 - applicable_percent / 100)
    def get_name(self): return "阶梯折扣"

class ShoppingCart:
    def __init__(self, discount_strategy=None):
        self._items = []
        self._strategy = discount_strategy or NoDiscount()

    def add_item(self, name, price): self._items.append((name, price))
    def set_strategy(self, strategy): self._strategy = strategy

    def checkout(self):
        original_price = sum(price for _, price in self._items)
        final_price = self._strategy.calculate(original_price)
        savings = original_price - final_price
        print(f"  原价: ¥{original_price:.2f}")
        print(f"  策略: {self._strategy.get_name()}")
        print(f"  折后价: ¥{final_price:.2f}")
        print(f"  节省: ¥{savings:.2f}")
        return final_price

# ========== 观察者模式 ==========

class StockSubject:
    """股票主题"""
    def __init__(self, symbol, name):
        self._symbol = symbol
        self._name = name
        self._price = 0.0
        self._observers = []

    def attach(self, observer):
        if observer not in self._observers:
            self._observers.append(observer)

    def notify(self):
        for observer in self._observers:
            observer.update(self)

    def set_price(self, price):
        old_price = self._price
        self._price = price
        change_pct = ((price - old_price) / old_price * 100) if old_price > 0 else 0
        direction = "📈" if price > old_price else ("📉" if price < old_price else "➡️")
        print(f"    [{self._symbol}] 价格变动: {old_price:.2f} -> {price:.2f} ({direction} {change_pct:+.2f}%)")
        self.notify()

class Observer(ABC):
    @abstractmethod
    def update(self, subject): pass
    @abstractmethod
    def get_name(self): pass

class PriceDisplay(Observer):
    def get_name(self): return "价格显示器"
    def update(self, stock):
        print(f"      [显示器] {stock.symbol} 当前价格: ¥{stock.price:.2f}")

class AlertSystem(Observer):
    def __init__(self, upper_limit, lower_limit):
        self.upper_limit = upper_limit
        self.lower_limit = lower_limit
    def get_name(self): return "告警系统"
    def update(self, stock):
        if stock.price >= self.upper_limit:
            print(f"      [告警] 🔴 {stock.symbol} 超过上限!")
        elif stock.price <= self.lower_limit:
            print(f"      [告警] 🟢 {stock.symbol} 低于下限!")

class TradeLogger(Observer):
    def __init__(self): self.history = []
    def get_name(self): return "交易日志"
    def update(self, stock):
        entry = f"{time.strftime('%H:%M:%S')} | {stock.symbol} | ¥{stock.price:.2f}"
        self.history.append(entry)

# ========== 通用事件系统 ==========

class EventEmitter:
    def __init__(self): self._events = {}
    def on(self, event_name, callback):
        if event_name not in self._events:
            self._events[event_name] = []
        self._events[event_name].append(callback)
    def emit(self, event_name, *args, **kwargs):
        if event_name in self._events:
            for callback in self._events[event_name]:
                callback(*args, **kwargs)

上机输出

======================================================================
实验7:行为型 - 策略模式 & 观察者模式
======================================================================
----------------------------------------------------------------------
1. 策略模式 (Strategy Pattern)
----------------------------------------------------------------------

策略模式:定义一系列算法,将它们封装起来,使它们可以互相替换。
使算法的变化独立于使用算法的客户端。

适用场景:
  - 多种排序算法切换
  - 支付方式选择
  - 促销折扣策略
  - 路径规划算法选择

>>> 电商折扣策略示例

--- 使用策略: 无折扣 ---
  购物车商品:
    Python编程: ¥89.00
    机械键盘: ¥459.00
    鼠标垫: ¥29.00
  原价: ¥577.00
  策略: 无折扣
  折后价: ¥577.00
  节省: ¥0.00

--- 使用策略: 10%折扣 ---
  购物车商品:
    Python编程: ¥89.00
    机械键盘: ¥459.00
    鼠标垫: ¥29.00
  原价: ¥577.00
  策略: 10%折扣
  折后价: ¥519.30
  节省: ¥57.70

--- 使用策略: 减50元 ---
  购物车商品:
    Python编程: ¥89.00
    机械键盘: ¥459.00
    鼠标垫: ¥29.00
  原价: ¥577.00
  策略: 减50元
  折后价: ¥527.00
  节省: ¥50.00

--- 使用策略: 满500减100 ---
  购物车商品:
    Python编程: ¥89.00
    机械键盘: ¥459.00
    鼠标垫: ¥29.00
  原价: ¥577.00
  策略: 满500减100
  折后价: ¥477.00
  节省: ¥100.00

--- 使用策略: 阶梯折扣 ---
  购物车商品:
    Python编程: ¥89.00
    机械键盘: ¥459.00
    鼠标垫: ¥29.00
  原价: ¥577.00
  策略: 阶梯折扣
  折后价: ¥490.45
  节省: ¥86.55

----------------------------------------------------------------------
  排序策略示例
----------------------------------------------------------------------
  原始数据: [64, 34, 25, 12, 22, 11, 90, 5, 77, 30, 55, 1, 88, 43]
  [冒泡排序] 耗时: 0.000012s, 结果: [1, 5, 11, 12, 22, 25, 30, 34, 43, 55]...
  [快速排序] 耗时: 0.000015s, 结果: [1, 5, 11, 12, 22, 25, 30, 34, 43, 55]...
  [Python内置排序] 耗时: 0.000002s, 结果: [1, 5, 11, 12, 22, 25, 30, 34, 43, 55]...

----------------------------------------------------------------------
2. 观察者模式 (Observer Pattern)
----------------------------------------------------------------------

观察者模式:定义对象间的一对多依赖关系,当一个对象状态发生变化时,
所有依赖于它的对象都会得到通知并自动更新。

又称:发布-订阅模式 (Publish-Subscribe)

核心角色:
  - Subject(主题):被观察的对象,维护观察者列表
  - Observer(观察者):订阅主题变化的对象

应用场景:
  - 股票价格变动通知
  - 社交媒体关注通知
  - 事件驱动系统
  - MVC架构中的Model-View

>>> 股票价格监控示例
    [600519] 价格显示器 订阅了 贵州茅台
    [600519] 告警系统 订阅了 贵州茅台
    [600519] 交易日志 订阅了 贵州茅台

    [600519] 价格变动: 0.00 -> 1700.00 (📈 +0.00%)
      [显示器] 600519 当前价格: ¥1700.00
      [日志] 记录: 20:54:44 | 600519 | ¥1700.00

    [600519] 价格变动: 1700.00 -> 1750.50 (📈 +2.97%)
      [显示器] 600519 当前价格: ¥1750.50
      [日志] 记录: 20:54:44 | 600519 | ¥1750.50

    [600519] 价格变动: 1750.50 -> 1820.00 (📈 +3.97%)
      [显示器] 600519 当前价格: ¥1820.00
      [日志] 记录: 20:54:44 | 600519 | ¥1820.00

    [600519] 价格变动: 1820.00 -> 1600.00 (📉 -12.09%)
      [显示器] 600519 当前价格: ¥1600.00
      [告警] 🟢 600519 价格 ¥1600.00 低于下限 1600!
      [日志] 记录: 20:54:44 | 600519 | ¥1600.00

    [600519] 价格变动: 1600.00 -> 1550.00 (📉 -3.12%)
      [显示器] 600519 当前价格: ¥1550.00
      [告警] 🟢 600519 价格 ¥1550.00 低于下限 1600!
      [日志] 记录: 20:54:44 | 600519 | ¥1550.00

    [600519] 价格变动: 1550.00 -> 1850.00 (📈 +19.35%)
      [显示器] 600519 当前价格: ¥1850.00
      [日志] 记录: 20:54:44 | 600519 | ¥1850.00

    [600519] 价格变动: 1850.00 -> 1920.00 (📈 +3.78%)
      [显示器] 600519 当前价格: ¥1920.00
      [告警] 🔴 600519 价格 ¥1920.00 超过上限 1900!
      [日志] 记录: 20:54:44 | 600519 | ¥1920.00

  交易日志记录 (7 条):
    20:54:44 | 600519 | ¥1700.00
    20:54:44 | 600519 | ¥1750.50
    20:54:44 | 600519 | ¥1820.00
    20:54:44 | 600519 | ¥1600.00
    20:54:44 | 600519 | ¥1550.00
    20:54:44 | 600519 | ¥1850.00
    20:54:44 | 600519 | ¥1920.00

----------------------------------------------------------------------
  事件系统示例
----------------------------------------------------------------------
触发 user_login 事件:
    📧 发送欢迎邮件给 techstar
    📊 记录登录日志: techstar
    🎁 检查新用户礼包: techstar

触发 order_created 事件:
    📦 订单 ORD-2026-0705-001 已创建
    💳 触发支付流程: ORD-2026-0705-001
    📲 推送通知: 订单 ORD-2026-0705-001

======================================================================
实验7完成!策略模式和观察者模式均验证通过。
======================================================================

实验8:行为型 - 命令模式、模板方法模式

知识点

  1. 命令模式
  2. 模板方法模式

原理

命令模式:将请求封装为对象,从而可以用不同的请求对客户进行参数化。允许请求的排队、记录日志,以及支持撤销操作。

模板方法模式:在基类中定义算法的骨架,将具体步骤延迟到子类中实现。使子类可以不改变算法结构,就重新定义算法的某些步骤。

代码实现

# -*- coding: utf-8 -*-
"""
实验8:行为型 - 命令模式 & 模板方法模式
"""
from abc import ABC, abstractmethod
import time

# ========== 命令模式 ==========

# 接收者
class Light:
    def __init__(self, location):
        self.location = location
        self.on = False
    def turn_on(self):
        self.on = True
        print(f"    [{self.location}灯] 开启 💡")
    def turn_off(self):
        self.on = False
        print(f"    [{self.location}灯] 关闭")

class AirConditioner:
    def __init__(self):
        self.temperature = 26
        self.on = False
    def turn_on(self):
        self.on = True
        print(f"    [空调] 开启,温度: {self.temperature}°C")
    def turn_off(self):
        self.on = False
        print(f"    [空调] 关闭")
    def set_temperature(self, temp):
        self.temperature = temp
        print(f"    [空调] 温度设为 {temp}°C")

class Curtain:
    def __init__(self): self.open = False
    def open_curtain(self):
        self.open = True
        print(f"    [窗帘] 打开")
    def close_curtain(self):
        self.open = False
        print(f"    [窗帘] 关闭")

# 命令接口
class Command(ABC):
    @abstractmethod
    def execute(self): pass
    @abstractmethod
    def undo(self): pass

# 具体命令
class LightOnCommand(Command):
    def __init__(self, light): self.light = light
    def execute(self): self.light.turn_on()
    def undo(self): self.light.turn_off()

class LightOffCommand(Command):
    def __init__(self, light): self.light = light
    def execute(self): self.light.turn_off()
    def undo(self): self.light.turn_on()

class ACOnCommand(Command):
    def __init__(self, ac, temp=26):
        self.ac = ac; self.temp = temp; self.prev_temp = None
    def execute(self):
        self.prev_temp = self.ac.temperature
        self.ac.turn_on()
        self.ac.set_temperature(self.temp)
    def undo(self):
        if self.prev_temp: self.ac.set_temperature(self.prev_temp)
        self.ac.turn_off()

class CurtainCommand(Command):
    def __init__(self, curtain, should_open):
        self.curtain = curtain; self.should_open = should_open
    def execute(self):
        if self.should_open: self.curtain.open_curtain()
        else: self.curtain.close_curtain()
    def undo(self):
        if self.should_open: self.curtain.close_curtain()
        else: self.curtain.open_curtain()

# 宏命令
class MacroCommand(Command):
    def __init__(self, commands, name="宏命令"):
        self._commands = commands; self._name = name
    def execute(self):
        for cmd in self._commands: cmd.execute()
    def undo(self):
        for cmd in reversed(self._commands): cmd.undo()

# 调用者:遥控器
class RemoteControl:
    def __init__(self, slots=5):
        self._on_commands = [None] * slots
        self._off_commands = [None] * slots
        self._history = []
    def set_command(self, slot, on_cmd, off_cmd):
        self._on_commands[slot] = on_cmd
        self._off_commands[slot] = off_cmd
    def press_on(self, slot):
        cmd = self._on_commands[slot]
        if cmd: cmd.execute(); self._history.append(cmd)
    def press_off(self, slot):
        cmd = self._off_commands[slot]
        if cmd: cmd.execute(); self._history.append(cmd)
    def press_undo(self):
        if self._history:
            cmd = self._history.pop()
            cmd.undo()
    def execute_macro(self, macro):
        macro.execute()
        self._history.append(macro)

# ========== 模板方法模式 ==========

class DataPipeline(ABC):
    """数据处理流水线模板"""
    def run(self, source):
        raw_data = self.connect(source)
        extracted = self.extract(raw_data)
        transformed = self.transform(extracted)
        if not self.validate(transformed): return None
        self.load(transformed)
        self.cleanup()
        return transformed

    @abstractmethod
    def connect(self, source): pass
    @abstractmethod
    def extract(self, raw_data): pass
    @abstractmethod
    def transform(self, data): pass
    def validate(self, data): return True  # 钩子方法
    @abstractmethod
    def load(self, data): pass
    def cleanup(self): pass  # 钩子方法

class CSVDataPipeline(DataPipeline):
    def connect(self, source):
        print(f"    [连接] 打开CSV文件: {source}")
        return f"csv_content_of({source})"
    def extract(self, raw_data):
        return [{"id": 1, "name": "Alice", "score": 85},
                {"id": 2, "name": "Bob", "score": 92},
                {"id": 3, "name": "Charlie", "score": 78}]
    def transform(self, data):
        for row in data:
            if row["score"] >= 90: row["grade"] = "A"
            elif row["score"] >= 80: row["grade"] = "B"
            else: row["grade"] = "C"
        return data
    def load(self, data):
        for row in data:
            print(f"      INSERT INTO students VALUES ({row['id']}, '{row['name']}', {row['score']}, '{row['grade']}')")

class BeverageMaker(ABC):
    """饮料制作模板"""
    def prepare(self):
        self.boil_water()
        self.brew()
        self.pour_in_cup()
        if self.want_condiments():
            self.add_condiments()

    def boil_water(self): print("    1. 烧开水")
    @abstractmethod
    def brew(self): pass
    def pour_in_cup(self): print("    3. 倒入杯子")
    @abstractmethod
    def add_condiments(self): pass
    def want_condiments(self): return True  # 钩子方法

class TeaMaker(BeverageMaker):
    def brew(self): print("    2. 用沸水泡茶叶3分钟")
    def add_condiments(self): print("    4. 加柠檬片")

class CoffeeMaker(BeverageMaker):
    def brew(self): print("    2. 用沸水冲泡咖啡粉,滴滤2分钟")
    def add_condiments(self): print("    4. 加糖和牛奶")

class BlackCoffeeMaker(CoffeeMaker):
    def want_condiments(self): return False  # 黑咖啡不加调料

上机输出

======================================================================
实验8:行为型 - 命令模式 & 模板方法模式
======================================================================
----------------------------------------------------------------------
1. 命令模式 (Command Pattern)
----------------------------------------------------------------------

命令模式:将请求封装为对象,从而可以用不同的请求对客户进行参数化。
允许请求的排队、记录日志,以及支持撤销操作。

核心角色:
  - Command:命令接口
  - Receiver:接收者,执行实际工作
  - Invoker:调用者,持有命令并触发执行
  - Client:客户端,创建命令并组装

应用场景:
  - GUI按钮/菜单操作
  - 事务管理
  - 宏命令
  - 撤销/重做功能

>>> 智能家居遥控器示例
操作遥控器:
  [遥控器] 按下按钮[0] ON: 开启客厅灯
    [客厅灯] 开启 💡
  [遥控器] 按下按钮[1] ON: 开启卧室灯
    [卧室灯] 开启 💡
  [遥控器] 按下按钮[1] OFF: 关闭卧室灯
    [卧室灯] 关闭
  [遥控器] 按下按钮[3] ON: 打开窗帘
    [窗帘] 打开

撤销操作:
  [遥控器] 撤销: 打开窗帘
    [窗帘] 关闭
  [遥控器] 撤销: 关闭卧室灯
    [卧室灯] 开启 💡

执行宏命令 - 回家模式:
  [遥控器] 执行宏命令: 回家模式(开启客厅灯, 开启空调(26°C), 关闭窗帘)
    >>> 执行回家模式:
    [客厅灯] 开启 💡
    [空调] 开启,温度: 26°C
    [空调] 温度设为 26°C
    [窗帘] 关闭

执行宏命令 - 睡觉模式:
  [遥控器] 执行宏命令: 睡觉模式(关闭客厅灯, 关闭卧室灯, 开启空调(25°C), 关闭窗帘)
    >>> 执行睡觉模式:
    [客厅灯] 关闭
    [卧室灯] 关闭
    [空调] 开启,温度: 26°C
    [空调] 温度设为 25°C
    [窗帘] 关闭

撤销最后一个宏命令:
  [遥控器] 撤销: 睡觉模式(关闭客厅灯, 关闭卧室灯, 开启空调(25°C), 关闭窗帘)
    >>> 撤销睡觉模式:
    [窗帘] 打开
    [空调] 温度设为 26°C
    [空调] 关闭
    [卧室灯] 开启 💡
    [客厅灯] 开启 💡

----------------------------------------------------------------------
2. 模板方法模式 (Template Method Pattern)
----------------------------------------------------------------------

模板方法模式:在基类中定义算法的骨架,将具体步骤延迟到子类中实现。
使子类可以不改变算法结构,就重新定义算法的某些步骤。

核心思想:定义流程框架,具体实现交给子类

应用场景:
  - 数据处理流水线(ETL)
  - Web框架的请求处理
  - 测试框架的 setUp/test/tearDown
  - 各类报表生成

>>> 数据处理流水线 (ETL) 示例
运行CSV数据处理流水线:

  [==================== CSVDataPipeline ====================]
    [连接] 打开CSV文件: students.csv
    [提取] 解析CSV数据
    [转换] 添加等级字段
    [验证] 检查成绩范围和必填字段...
    [验证] 通过
    [加载] 写入数据库:
      INSERT INTO students VALUES (1, 'Alice', 85, 'B')
      INSERT INTO students VALUES (2, 'Bob', 92, 'A')
      INSERT INTO students VALUES (3, 'Charlie', 78, 'C')
    [清理] 释放资源
  [完成] 处理了 3 条记录

运行API数据处理流水线:

  [==================== APIDataPipeline ====================]
    [连接] HTTP请求: GET https://api.example.com/products
    [提取] 解析JSON响应
    [转换] 货币转换 USD -> CNY (汇率7.2)
    [验证] 检查价格有效性...
    [加载] 写入缓存:
      CACHE SET product:Widget = ¥143.93
      CACHE SET product:Gadget = ¥215.93
      CACHE SET product:Gizmo = ¥71.93
    [清理] 释放资源
  [完成] 处理了 3 条记录

运行日志处理流水线:

  [==================== LogPipeline ====================]
    [连接] 打开日志文件: /var/log/app.log
    [提取] 读取日志行
    [转换] 解析日志格式
    [验证] 检查日志格式...
    [加载] 存入Elasticsearch:
      ℹ️ [2026-07-05 10:00:01] INFO: User login: admin
      🔴 [2026-07-05 10:00:05] ERROR: Database connection failed
      🟡 [2026-07-05 10:00:10] WARN: Cache miss rate high
      ℹ️ [2026-07-05 10:00:15] INFO: User logout: admin
    [清理] 释放资源
  [完成] 处理了 4 条记录

----------------------------------------------------------------------
  模板方法 - 饮料制作示例
----------------------------------------------------------------------

  === 制作茶 ===
    1. 烧开水
    2. 用沸水泡茶叶3分钟
    3. 倒入杯子
    4. 加柠檬片
  === 茶 制作完成 ===

  === 制作咖啡 ===
    1. 烧开水
    2. 用沸水冲泡咖啡粉,滴滤2分钟
    3. 倒入杯子
    4. 加糖和牛奶
  === 咖啡 制作完成 ===

  === 制作黑咖啡 ===
    1. 烧开水
    2. 用沸水冲泡咖啡粉,滴滤2分钟
    3. 倒入杯子
  === 黑咖啡 制作完成 ===

======================================================================
实验8完成!命令模式和模板方法模式均验证通过。
======================================================================

设计模式总览

三大类设计模式一览表

分类 模式 核心思想 关键角色 实验编号
创建型 单例模式 确保唯一实例 Singleton 实验1
创建型 元类 控制类的创建过程 type/Meta 实验2
创建型 简单工厂 参数化创建对象 Factory 实验3
创建型 工厂方法 子类决定创建 Creator/Product 实验3
创建型 抽象工厂 创建产品族 AbstractFactory 实验3
结构型 适配器模式 接口转换 Adapter/Target 实验4
结构型 装饰器模式 动态添加职责 Decorator/Component 实验4
结构型 代理模式 控制访问 Proxy/Subject 实验5
结构型 组合模式 树形结构 Composite/Leaf 实验5
结构型 外观模式 简化接口 Facade 实验6
结构型 享元模式 共享对象 Flyweight/Factory 实验6
行为型 策略模式 算法封装替换 Strategy/Context 实验7
行为型 观察者模式 发布-订阅 Subject/Observer 实验7
行为型 命令模式 请求封装 Command/Invoker 实验8
行为型 模板方法 算法骨架 Template/Hook 实验8

设计模式六大原则

原则 全称 说明
SRP 单一职责原则 一个类应该只有一个引起变化的原因
OCP 开闭原则 对扩展开放,对修改关闭
LSP 里氏替换原则 子类必须能够替换父类
DIP 依赖倒置原则 依赖抽象,不依赖具体
ISP 接口隔离原则 客户端不应依赖不需要的接口
LoD 迪米特法则 最少知识原则,减少耦合

实验环境信息

项目 信息
服务器 ecs-5d9b-0001 (c6s.2xlarge.2, 8vCPUs, 16GiB)
操作系统 Ubuntu 24.04.4 LTS server 64bit
弹性公网IP 119.8.30.110
私有IP 192.168.0.186
Python版本 3.12.3
实验日期 2026-07-05

源码文件清单

文件 内容
exp1_singleton.py 单例模式三种实现(模块/__new__/装饰器)+ 线程安全测试
exp2_metaclass.py 元类 __new__/__init__/__call__ + ORM 示例
exp3_factory.py 抽象类 + 简单工厂 + 工厂方法 + 抽象工厂
exp4_adapter_decorator.py 日志适配器 + 咖啡装饰器 + 函数装饰器 + 类装饰器
exp5_proxy_composite.py 虚拟代理 + 保护代理 + 文件系统组合 + 组织架构组合
exp6_facade_flyweight.py 电脑外观 + 家庭影院 + 文档享元 + 围棋享元
exp7_strategy_observer.py 折扣策略 + 排序策略 + 股票观察者 + 事件系统
exp8_command_template.py 智能家居命令 + 宏命令 + ETL流水线 + 饮料制作模板

更多推荐