Python 设计模式实践
Python 设计模式实践
实验环境:Python 3.12.3 | ECS服务器 ecs-5d9b-0001 (192.168.0.186)
实验时间:2026-07-05
实验内容:8个实验,覆盖创建型、结构型、行为型三大类共14种设计模式
目录
- 课程概述
- 实验1:创建型 - 单例模式
- 实验2:Python 元类简介与使用
- 实验3:创建型 - 工厂模式
- 实验4:结构型 - 适配器模式、装饰器模式
- 实验5:结构型 - 代理模式、组合模式
- 实验6:结构型 - 外观模式、享元模式
- 实验7:行为型 - 策略模式、观察者模式
- 实验8:行为型 - 命令模式、模板方法模式
- 设计模式总览
课程概述
设计模式是软件设计中常见问题的可复用解决方案。它们不是可以直接转换为代码的模板,而是解决特定问题的最佳实践。本课程以蓝桥云课功能为案例背景,使用 Python 为实现语言,系统学习14种常见设计模式。
设计模式分为三大类:
| 分类 | 关注点 | 包含模式 |
|---|---|---|
| 创建型模式 | 对象的创建机制 | 单例、工厂方法、抽象工厂 |
| 结构型模式 | 类和对象的组合 | 适配器、装饰器、代理、组合、外观、享元 |
| 行为型模式 | 对象之间的通信 | 策略、观察者、命令、模板方法 |
实验1:创建型 - 单例模式
知识点
- 设计模式简介
- 单例模式的三种实现方式
原理
单例模式(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 元类简介与使用
知识点
- 元类的概念
- 利用
__new__方法控制类的属性 - 利用
__init__方法控制类的属性 - 利用
__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:创建型 - 工厂模式
知识点
- 抽象类
- 简单工厂模式
- 工厂方法模式
- 抽象工厂模式
原理
工厂模式是最常用的设计模式之一,用于创建对象时隐藏创建逻辑。
代码实现
# -*- 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:结构型 - 适配器模式、装饰器模式
知识点
- 适配器模式
- 装饰器模式
原理
适配器模式:将一个类的接口转换成客户端期望的另一个接口,使原本接口不兼容的类可以一起工作。生活中的例子包括 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:结构型 - 代理模式、组合模式
知识点
- 代理模式
- 组合模式
原理
代理模式:为其他对象提供代理以控制对这个对象的访问。包括虚拟代理(延迟加载)、保护代理(权限控制)等。
组合模式:将对象组合成树形结构来表示"部分-整体"的层次结构,使客户端可以统一处理单个对象和组合对象。
代码实现
# -*- 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:结构型 - 外观模式、享元模式
知识点
- 外观模式
- 享元模式
原理
外观模式:为子系统中的一组接口提供一个一致的界面,定义一个高层接口使子系统更容易使用。
享元模式:通过共享对象来减少内存使用和提高性能,适用于大量相似对象的场景。核心概念是区分内部状态(可共享)和外部状态(不可共享)。
代码实现
# -*- 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:行为型 - 策略模式、观察者模式
知识点
- 策略模式
- 观察者模式
原理
策略模式:定义一系列算法,将它们封装起来,使它们可以互相替换。使算法的变化独立于使用算法的客户端。
观察者模式:定义对象间的一对多依赖关系,当一个对象状态发生变化时,所有依赖于它的对象都会得到通知并自动更新。又称发布-订阅模式。
代码实现
# -*- 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:行为型 - 命令模式、模板方法模式
知识点
- 命令模式
- 模板方法模式
原理
命令模式:将请求封装为对象,从而可以用不同的请求对客户进行参数化。允许请求的排队、记录日志,以及支持撤销操作。
模板方法模式:在基类中定义算法的骨架,将具体步骤延迟到子类中实现。使子类可以不改变算法结构,就重新定义算法的某些步骤。
代码实现
# -*- 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流水线 + 饮料制作模板 |
更多推荐



所有评论(0)