{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Python 设计模式教程\n", "\n", "欢迎来到 Python 设计模式教程!设计模式是软件开发中针对常见问题的经过验证的、可重用的解决方案。它们不是具体的代码或库,而是一种描述问题和解决方案之间关系的方式,可以帮助你编写更灵活、可维护和可扩展的代码。\n", "\n", "Python 是一种动态且富有表现力的语言,其许多特性(如函数是一等公民、动态类型、鸭子类型)使得某些设计模式的实现比在静态类型语言中更简洁或有所不同。\n", "\n", "**为什么学习设计模式?**\n", "\n", "1. **提供通用词汇**:开发者之间可以更有效地沟通设计思想。\n", "2. **重用经验证的解决方案**:避免重复造轮子,解决常见设计问题。\n", "3. **提高代码质量**:使代码更易于理解、修改和维护。\n", "4. **促进代码复用**:模式本身就是可复用的思想。\n", "\n", "**设计模式分类 (GoF - Gang of Four 经典分类):**\n", "\n", "* **创建型模式 (Creational Patterns)**:关注对象的创建机制,旨在以适合特定情况的方式创建对象。\n", "* **结构型模式 (Structural Patterns)**:关注类和对象的组合,形成更大的结构。\n", "* **行为型模式 (Behavioral Patterns)**:关注对象之间的职责分配和算法的抽象。\n", "\n", "本教程将介绍一些常见的设计模式及其在 Python 中的 Pythonic 实现。" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 1. 创建型模式 (Creational Patterns)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### 1.1 工厂方法 (Factory Method)\n", "\n", "**意图**:定义一个创建对象的接口,但让子类决定实例化哪一个类。工厂方法使一个类的实例化延迟到其子类。\n", "\n", "**Pythonic 实现**:在 Python 中,由于函数是一等公民,工厂方法通常可以直接用一个返回不同类型实例的函数或静态方法来实现,不一定需要严格的类继承结构。" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "from abc import ABC, abstractmethod\n", "\n", "# 产品接口\n", "class Document(ABC):\n", " @abstractmethod\n", " def open(self):\n", " pass\n", "\n", "# 具体产品\n", "class TextDocument(Document):\n", " def open(self):\n", " print(\"Opening text document...\")\n", " return \"Text Content\"\n", "\n", "class PdfDocument(Document):\n", " def open(self):\n", " print(\"Opening PDF document...\")\n", " return \"PDF Content\"\n", "\n", "# 创建者 (工厂) - 经典方式\n", "class DocumentFactory(ABC):\n", " @abstractmethod\n", " def create_document(self) -> Document:\n", " pass\n", "\n", " def process_document(self):\n", " doc = self.create_document()\n", " content = doc.open()\n", " print(f\"Processing content: {content}\")\n", "\n", "# 具体创建者\n", "class TextDocumentFactory(DocumentFactory):\n", " def create_document(self) -> Document:\n", " return TextDocument()\n", "\n", "class PdfDocumentFactory(DocumentFactory):\n", " def create_document(self) -> Document:\n", " return PdfDocument()\n", "\n", "print(\"--- Classic Factory Method ---\")\n", "text_factory = TextDocumentFactory()\n", "text_factory.process_document()\n", "\n", "pdf_factory = PdfDocumentFactory()\n", "pdf_factory.process_document()\n", "\n", "# Pythonic 工厂函数\n", "def create_document_pythonic(doc_type: str) -> Document:\n", " if doc_type == 'text':\n", " return TextDocument()\n", " elif doc_type == 'pdf':\n", " return PdfDocument()\n", " else:\n", " raise ValueError(f\"Unknown document type: {doc_type}\")\n", "\n", "print(\"\\n--- Pythonic Factory Function ---\")\n", "doc1 = create_document_pythonic('text')\n", "print(doc1.open())\n", "doc2 = create_document_pythonic('pdf')\n", "print(doc2.open())" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### 1.2 抽象工厂 (Abstract Factory)\n", "\n", "**意图**:提供一个接口,用于创建一系列相关或相互依赖的对象,而无需指定它们具体的类。\n", "\n", "**场景**:当你的系统需要独立于其产品的创建、组合和表示时,或者当你有多个产品系列,并且希望在任何给定时间只使用一个系列时。" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# 抽象产品 A\n", "class Button(ABC):\n", " @abstractmethod\n", " def paint(self):\n", " pass\n", "\n", "# 抽象产品 B\n", "class Checkbox(ABC):\n", " @abstractmethod\n", " def paint(self):\n", " pass\n", "\n", "# 具体产品 (Windows 主题)\n", "class WinButton(Button):\n", " def paint(self):\n", " print(\"Painting Windows button\")\n", "\n", "class WinCheckbox(Checkbox):\n", " def paint(self):\n", " print(\"Painting Windows checkbox\")\n", "\n", "# 具体产品 (Mac 主题)\n", "class MacButton(Button):\n", " def paint(self):\n", " print(\"Painting Mac button\")\n", "\n", "class MacCheckbox(Checkbox):\n", " def paint(self):\n", " print(\"Painting Mac checkbox\")\n", "\n", "# 抽象工厂\n", "class GUIFactory(ABC):\n", " @abstractmethod\n", " def create_button(self) -> Button:\n", " pass\n", "\n", " @abstractmethod\n", " def create_checkbox(self) -> Checkbox:\n", " pass\n", "\n", "# 具体工厂 (Windows)\n", "class WinFactory(GUIFactory):\n", " def create_button(self) -> Button:\n", " return WinButton()\n", "\n", " def create_checkbox(self) -> Checkbox:\n", " return WinCheckbox()\n", "\n", "# 具体工厂 (Mac)\n", "class MacFactory(GUIFactory):\n", " def create_button(self) -> Button:\n", " return MacButton()\n", "\n", " def create_checkbox(self) -> Checkbox:\n", " return MacCheckbox()\n", "\n", "# 客户端代码\n", "def create_ui(factory: GUIFactory):\n", " button = factory.create_button()\n", " checkbox = factory.create_checkbox()\n", " button.paint()\n", " checkbox.paint()\n", "\n", "print(\"--- Abstract Factory ---\")\n", "print(\"Client: Creating UI with Windows theme\")\n", "create_ui(WinFactory())\n", "\n", "print(\"\\nClient: Creating UI with Mac theme\")\n", "create_ui(MacFactory())" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### 1.3 单例模式 (Singleton)\n", "\n", "**意图**:确保一个类只有一个实例,并提供一个全局访问点来访问该实例。\n", "\n", "**Pythonic 实现**:在 Python 中,由于模块本身在导入时就是单例的,所以一种常见的做法是使用模块级变量。如果确实需要类实现单例,可以使用元类、装饰器或覆盖 `__new__` 方法。\n", "\n", "**争议**:单例模式有时被认为是反模式,因为它引入了全局状态,可能使测试和代码理解变得困难。应谨慎使用。" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# 方法1: 使用元类\n", "class SingletonMeta(type):\n", " _instances = {}\n", " def __call__(cls, *args, **kwargs):\n", " if cls not in cls._instances:\n", " instance = super().__call__(*args, **kwargs)\n", " cls._instances[cls] = instance\n", " return cls._instances[cls]\n", "\n", "class Logger(metaclass=SingletonMeta):\n", " def __init__(self, filename):\n", " # 注意:__init__ 仍然会在每次尝试创建时被调用,即使返回的是现有实例\n", " # 因此,初始化逻辑可能需要特殊处理,确保只执行一次\n", " if not hasattr(self, 'filename'): # 简单检查避免重复初始化\n", " print(f\"Logger (metaclass) initialized with {filename}\")\n", " self.filename = filename\n", " \n", " def log(self, message):\n", " print(f\"LOG [{self.filename}]: {message}\")\n", "\n", "print(\"--- Singleton with Metaclass ---\")\n", "logger1 = Logger(\"app.log\")\n", "logger2 = Logger(\"another.log\") # __init__ 会被调用,但返回的是 logger1\n", "logger1.log(\"Event 1\")\n", "logger2.log(\"Event 2\") # 使用的还是 app.log\n", "print(f\"logger1 is logger2: {logger1 is logger2}\")\n", "print(f\"logger1.filename: {logger1.filename}\") # 仍是 app.log\n", "\n", "# 方法2: 使用装饰器 (更简洁,但 __init__ 行为类似)\n", "def singleton_decorator(cls):\n", " instances = {}\n", " def get_instance(*args, **kwargs):\n", " if cls not in instances:\n", " instances[cls] = cls(*args, **kwargs)\n", " return instances[cls]\n", " return get_instance\n", "\n", "@singleton_decorator\n", "class DatabaseConnection:\n", " def __init__(self, dsn):\n", " if not hasattr(self, 'dsn'): # 简单检查避免重复初始化\n", " print(f\"DatabaseConnection (decorator) initialized with {dsn}\")\n", " self.dsn = dsn\n", " self.connection_id = id(self) # 只是为了演示\n", " \n", " def query(self, sql):\n", " print(f\"Querying on {self.dsn} (ID: {self.connection_id}): {sql}\")\n", "\n", "print(\"\\n--- Singleton with Decorator ---\")\n", "db1 = DatabaseConnection(\"user:pass@host1/db\")\n", "db2 = DatabaseConnection(\"user:pass@host2/db\")\n", "db1.query(\"SELECT * FROM users\")\n", "db2.query(\"SELECT * FROM products\") # 使用的还是 host1\n", "print(f\"db1 is db2: {db1 is db2}\")\n", "\n", "# 方法3: 模块级单例 (最 Pythonic 的方式之一)\n", "# my_config.py\n", "class AppConfig:\n", " def __init__(self):\n", " self.settings = {}\n", " print(\"AppConfig (module level) initialized\")\n", " def set(self, key, value):\n", " self.settings[key] = value\n", " def get(self, key):\n", " return self.settings.get(key)\n", "\n", "# config_instance = AppConfig() # 在模块中创建实例\n", "# # 在其他地方: from my_config import config_instance\n", "print(\"\\n--- Singleton with Module ---\")\n", "class ModuleSingletonSimulation: # 模拟模块导入行为\n", " _instance = None\n", " @classmethod\n", " def get_instance(cls):\n", " if cls._instance is None:\n", " cls._instance = AppConfig()\n", " return cls._instance\n", "\n", "config1 = ModuleSingletonSimulation.get_instance()\n", "config2 = ModuleSingletonSimulation.get_instance()\n", "config1.set(\"theme\", \"dark\")\n", "print(f\"config2 theme: {config2.get('theme')}\")\n", "print(f\"config1 is config2: {config1 is config2}\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 2. 结构型模式 (Structural Patterns)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### 2.1 适配器模式 (Adapter)\n", "\n", "**意图**:将一个类的接口转换成客户希望的另一个接口。适配器使原本由于接口不兼容而不能一起工作的那些类可以一起工作。\n", "\n", "**场景**:当你希望使用某个类,但是其接口与其他代码不兼容时。" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# 目标接口 (Target)\n", "class ModernLogger:\n", " def log_message(self, level: str, message: str):\n", " print(f\"MODERN LOG [{level.upper()}]: {message}\")\n", "\n", "# 被适配者 (Adaptee) - 一个老的、接口不同的日志库\n", "class LegacyLogger:\n", " def write_log(self, text: str, severity_code: int):\n", " # severity_code: 1=INFO, 2=WARNING, 3=ERROR\n", " severity_map = {1: \"INFO\", 2: \"WARN\", 3: \"ERR\"}\n", " print(f\"LEGACY LOG ({severity_map.get(severity_code, 'UNK')}): {text}\")\n", "\n", "# 适配器 (Adapter)\n", "class LoggerAdapter(ModernLogger):\n", " def __init__(self, legacy_logger: LegacyLogger):\n", " self._legacy_logger = legacy_logger\n", "\n", " def log_message(self, level: str, message: str):\n", " # 将 ModernLogger 的接口调用转换为 LegacyLogger 的接口调用\n", " level_map = {\"INFO\": 1, \"WARNING\": 2, \"ERROR\": 3}\n", " severity_code = level_map.get(level.upper(), 1) # 默认为 INFO\n", " self._legacy_logger.write_log(message, severity_code)\n", "\n", "print(\"--- Adapter Pattern ---\")\n", "legacy_logger_instance = LegacyLogger()\n", "adapter = LoggerAdapter(legacy_logger_instance)\n", "\n", "# 客户端现在可以使用 ModernLogger 接口与 LegacyLogger 交互\n", "adapter.log_message(\"info\", \"This is an informational message.\")\n", "adapter.log_message(\"ERROR\", \"A critical error occurred!\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### 2.2 装饰器模式 (Decorator) - 结构型\n", "\n", "**意图**:动态地给一个对象添加一些额外的职责。就增加功能来说,装饰器模式相比生成子类更为灵活。\n", "\n", "**注意**:这里的“装饰器模式”是 GoF 设计模式中的一种结构型模式,它与 Python 语言特性中的“装饰器”(@-syntax) 虽然名称相同且有相似之处(都是包装),但概念上是独立的。Python 装饰器语法是实现装饰器模式的一种非常自然的方式。\n", "\n", "**场景**:当你希望在不影响其他对象的情况下,以动态、透明的方式给单个对象添加职责。" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# 组件接口 (Component)\n", "class Coffee(ABC):\n", " @abstractmethod\n", " def get_cost(self) -> float:\n", " pass\n", "\n", " @abstractmethod\n", " def get_description(self) -> str:\n", " pass\n", "\n", "# 具体组件 (Concrete Component)\n", "class SimpleCoffee(Coffee):\n", " def get_cost(self) -> float:\n", " return 5.0\n", "\n", " def get_description(self) -> str:\n", " return \"Simple coffee\"\n", "\n", "# 装饰器基类 (Decorator Base)\n", "class CoffeeDecorator(Coffee):\n", " def __init__(self, wrapped_coffee: Coffee):\n", " self._wrapped_coffee = wrapped_coffee\n", "\n", " @abstractmethod\n", " def get_cost(self) -> float:\n", " pass\n", "\n", " @abstractmethod\n", " def get_description(self) -> str:\n", " pass\n", "\n", "# 具体装饰器 (Concrete Decorators)\n", "class MilkDecorator(CoffeeDecorator):\n", " def get_cost(self) -> float:\n", " return self._wrapped_coffee.get_cost() + 1.5\n", "\n", " def get_description(self) -> str:\n", " return self._wrapped_coffee.get_description() + \", milk\"\n", "\n", "class SugarDecorator(CoffeeDecorator):\n", " def get_cost(self) -> float:\n", " return self._wrapped_coffee.get_cost() + 0.5\n", "\n", " def get_description(self) -> str:\n", " return self._wrapped_coffee.get_description() + \", sugar\"\n", "\n", "print(\"--- Decorator Pattern (Structural) ---\")\n", "my_coffee = SimpleCoffee()\n", "print(f\"Coffee: {my_coffee.get_description()}, Cost: ${my_coffee.get_cost():.2f}\")\n", "\n", "# 加牛奶\n", "my_coffee = MilkDecorator(my_coffee)\n", "print(f\"Coffee: {my_coffee.get_description()}, Cost: ${my_coffee.get_cost():.2f}\")\n", "\n", "# 加糖\n", "my_coffee = SugarDecorator(my_coffee)\n", "print(f\"Coffee: {my_coffee.get_description()}, Cost: ${my_coffee.get_cost():.2f}\")\n", "\n", "# 再加一份牛奶 (可以多次装饰)\n", "my_coffee_double_milk = MilkDecorator(MilkDecorator(SimpleCoffee()))\n", "print(f\"Coffee: {my_coffee_double_milk.get_description()}, Cost: ${my_coffee_double_milk.get_cost():.2f}\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### 2.3 外观模式 (Facade)\n", "\n", "**意图**:为子系统中的一组接口提供一个统一的、高层的接口。外观定义了一个高层接口,使得子系统更容易使用。\n", "\n", "**场景**:当你想为一个复杂的子系统提供一个简单的接口时,或者你想将子系统与客户端解耦。" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# 复杂的子系统组件\n", "class CPU:\n", " def freeze(self):\n", " print(\"CPU: Freezing...\")\n", " def jump(self, position):\n", " print(f\"CPU: Jumping to {position}...\")\n", " def execute(self):\n", " print(\"CPU: Executing...\")\n", "\n", "class Memory:\n", " def load(self, position, data):\n", " print(f\"Memory: Loading data '{data}' to position {position}...\")\n", "\n", "class HardDrive:\n", " def read(self, lba, size):\n", " print(f\"HardDrive: Reading {size} bytes from LBA {lba}...\")\n", " return \"boot_data\"\n", "\n", "# 外观 (Facade)\n", "class ComputerFacade:\n", " def __init__(self):\n", " self.cpu = CPU()\n", " self.memory = Memory()\n", " self.hard_drive = HardDrive()\n", "\n", " def start(self):\n", " print(\"\\n--- ComputerFacade: Starting computer ---\")\n", " self.cpu.freeze()\n", " boot_address = 0x0000\n", " boot_sector_data = self.hard_drive.read(lba=0, size=512)\n", " self.memory.load(boot_address, boot_sector_data)\n", " self.cpu.jump(boot_address)\n", " self.cpu.execute()\n", " print(\"--- ComputerFacade: Computer started ---\")\n", "\n", "print(\"--- Facade Pattern ---\")\n", "computer = ComputerFacade()\n", "computer.start() # 客户端只需要调用一个简单的方法" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 3. 行为型模式 (Behavioral Patterns)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### 3.1 策略模式 (Strategy)\n", "\n", "**意图**:定义一系列算法,把它们一个个封装起来,并且使它们可以相互替换。策略模式使得算法可独立于使用它的客户而变化。\n", "\n", "**Pythonic 实现**:由于函数是一等公民,策略可以直接是函数,而不是必须是实现了特定接口的类。" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "from typing import List, Callable\n", "\n", "# 策略接口 (经典方式,Python中常直接用Callable)\n", "class SortStrategy(ABC):\n", " @abstractmethod\n", " def sort(self, data: List[int]) -> List[int]:\n", " pass\n", "\n", "# 具体策略\n", "class BubbleSortStrategy(SortStrategy):\n", " def sort(self, data: List[int]) -> List[int]:\n", " print(\"Sorting using Bubble Sort\")\n", " arr = list(data) # 创建副本以避免修改原始列表\n", " n = len(arr)\n", " for i in range(n):\n", " for j in range(0, n - i - 1):\n", " if arr[j] > arr[j + 1]:\n", " arr[j], arr[j + 1] = arr[j + 1], arr[j]\n", " return arr\n", "\n", "class QuickSortStrategy(SortStrategy):\n", " def sort(self, data: List[int]) -> List[int]:\n", " print(\"Sorting using Quick Sort (simplified)\")\n", " arr = list(data)\n", " # 实际的快速排序实现会更复杂,这里用内置排序代替简化\n", " arr.sort() \n", " return arr\n", "\n", "# 上下文 (Context)\n", "class Sorter:\n", " def __init__(self, strategy: SortStrategy = None):\n", " self._strategy = strategy or QuickSortStrategy() # 默认策略\n", "\n", " def set_strategy(self, strategy: SortStrategy):\n", " self._strategy = strategy\n", "\n", " def sort_data(self, data: List[int]) -> List[int]:\n", " return self._strategy.sort(data)\n", "\n", "print(\"--- Strategy Pattern (Classic) ---\")\n", "data_to_sort = [5, 1, 4, 2, 8]\n", "sorter = Sorter() # 默认使用 QuickSort\n", "print(f\"Sorted (default): {sorter.sort_data(data_to_sort)}\")\n", "\n", "sorter.set_strategy(BubbleSortStrategy())\n", "print(f\"Sorted (bubble): {sorter.sort_data(data_to_sort)}\")\n", "\n", "# Pythonic 策略 (使用函数)\n", "def bubble_sort_func(data: List[int]) -> List[int]:\n", " print(\"Sorting using Bubble Sort (function)\")\n", " # ... (实现同上)\n", " arr = list(data)\n", " n = len(arr)\n", " for i in range(n):\n", " for j in range(0, n - i - 1):\n", " if arr[j] > arr[j + 1]:\n", " arr[j], arr[j + 1] = arr[j + 1], arr[j]\n", " return arr\n", "\n", "def quick_sort_func(data: List[int]) -> List[int]:\n", " print(\"Sorting using Quick Sort (function)\")\n", " arr = list(data)\n", " arr.sort()\n", " return arr\n", "\n", "class PythonicSorter:\n", " def __init__(self, strategy_func: Callable[[List[int]], List[int]] = quick_sort_func):\n", " self._strategy_func = strategy_func\n", "\n", " def set_strategy(self, strategy_func: Callable[[List[int]], List[int]]):\n", " self._strategy_func = strategy_func\n", "\n", " def sort_data(self, data: List[int]) -> List[int]:\n", " return self._strategy_func(data)\n", "\n", "print(\"\\n--- Strategy Pattern (Pythonic Functions) ---\")\n", "py_sorter = PythonicSorter()\n", "print(f\"Sorted (default func): {py_sorter.sort_data(data_to_sort)}\")\n", "\n", "py_sorter.set_strategy(bubble_sort_func)\n", "print(f\"Sorted (bubble func): {py_sorter.sort_data(data_to_sort)}\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### 3.2 观察者模式 (Observer)\n", "\n", "**意图**:定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并自动更新。\n", "\n", "**场景**:当一个对象的改变需要同时改变其他对象,而且你不知道具体有多少对象需要改变时。或者当一个对象应该能通知其他对象,而不需要知道那些对象是谁时。" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# 主题 (Subject / Observable)\n", "class Subject:\n", " def __init__(self):\n", " self._observers: List[Callable] = [] # 存储观察者 (回调函数)\n", " self._state = None\n", "\n", " def attach(self, observer: Callable):\n", " if observer not in self._observers:\n", " self._observers.append(observer)\n", "\n", " def detach(self, observer: Callable):\n", " try:\n", " self._observers.remove(observer)\n", " except ValueError:\n", " pass # Observer not found\n", "\n", " def notify(self):\n", " print(\"Subject: Notifying observers...\")\n", " for observer in self._observers:\n", " observer(self._state) # 传递状态给观察者\n", "\n", " @property\n", " def state(self):\n", " return self._state\n", "\n", " @state.setter\n", " def state(self, new_state):\n", " print(f\"Subject: State changed to {new_state}\")\n", " self._state = new_state\n", " self.notify()\n", "\n", "# 观察者 (可以是函数或实现了特定接口的类)\n", "def concrete_observer_A(state):\n", " print(f\"Observer A: Received update, new state is {state}\")\n", "\n", "class ConcreteObserverB:\n", " def __init__(self, name):\n", " self.name = name\n", "\n", " def update(self, state):\n", " print(f\"Observer {self.name}: Received update, new state is {state}\")\n", "\n", "print(\"--- Observer Pattern ---\")\n", "subject = Subject()\n", "\n", "observer_b_instance = ConcreteObserverB(\"B1\")\n", "\n", "subject.attach(concrete_observer_A)\n", "subject.attach(observer_b_instance.update) # 传递方法作为回调\n", "\n", "subject.state = \"NEW_DATA_1\"\n", "print(\"-\")\n", "subject.state = \"MORE_DATA_2\"\n", "\n", "subject.detach(concrete_observer_A)\n", "print(\"-\")\n", "subject.state = \"FINAL_DATA_3\"" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### 3.3 命令模式 (Command)\n", "\n", "**意图**:将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化;对请求排队或记录请求日志,以及支持可撤销的操作。\n", "\n", "**场景**:当你想把发出请求的对象与执行请求的对象解耦,或者想支持撤销/重做操作、事务等。" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# 命令接口 (Command)\n", "class Command(ABC):\n", " @abstractmethod\n", " def execute(self):\n", " pass\n", "\n", " # 可选的撤销方法\n", " # @abstractmethod\n", " # def undo(self):\n", " # pass\n", "\n", "# 接收者 (Receiver) - 实际执行操作的对象\n", "class Light:\n", " def __init__(self, location: str):\n", " self.location = location\n", " self.is_on = False\n", "\n", " def turn_on(self):\n", " self.is_on = True\n", " print(f\"Light in {self.location} turned ON\")\n", "\n", " def turn_off(self):\n", " self.is_on = False\n", " print(f\"Light in {self.location} turned OFF\")\n", "\n", "# 具体命令 (Concrete Commands)\n", "class LightOnCommand(Command):\n", " def __init__(self, light: Light):\n", " self._light = light\n", "\n", " def execute(self):\n", " self._light.turn_on()\n", "\n", "class LightOffCommand(Command):\n", " def __init__(self, light: Light):\n", " self._light = light\n", "\n", " def execute(self):\n", " self._light.turn_off()\n", "\n", "# 调用者 (Invoker) - 持有命令并请求执行\n", "class RemoteControl:\n", " def __init__(self):\n", " self._command: Command = None\n", "\n", " def set_command(self, command: Command):\n", " self._command = command\n", "\n", " def press_button(self):\n", " if self._command:\n", " print(\"Remote: Button pressed\")\n", " self._command.execute()\n", " else:\n", " print(\"Remote: No command set\")\n", "\n", "print(\"--- Command Pattern ---\")\n", "living_room_light = Light(\"Living Room\")\n", "kitchen_light = Light(\"Kitchen\")\n", "\n", "light_on_living = LightOnCommand(living_room_light)\n", "light_off_living = LightOffCommand(living_room_light)\n", "light_on_kitchen = LightOnCommand(kitchen_light)\n", "\n", "remote = RemoteControl()\n", "\n", "remote.set_command(light_on_living)\n", "remote.press_button()\n", "\n", "remote.set_command(light_off_living)\n", "remote.press_button()\n", "\n", "remote.set_command(light_on_kitchen)\n", "remote.press_button()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 总结\n", "\n", "设计模式为构建健壮、可维护的软件提供了宝贵的指导。\n", "\n", "* **创建型模式** 帮助你以灵活的方式创建对象。\n", "* **结构型模式** 帮助你组合对象形成更大的结构。\n", " * Python 的动态性和鸭子类型有时可以简化结构型模式的实现,例如,对于适配器,有时只需要一个简单的包装函数或类,而不必严格遵循接口继承。\n", "* **行为型模式** 帮助你管理对象之间的交互和职责分配。\n", " * Python 的一等函数特性使得许多行为型模式(如策略、命令、观察者中的回调)可以非常简洁地实现。\n", "\n", "**学习设计模式的关键:**\n", "\n", "1. **理解意图**:每个模式解决什么问题?\n", "2. **了解结构**:模式中涉及哪些角色(类或对象)以及它们如何交互?\n", "3. **思考适用场景**:什么时候应该使用这个模式?什么时候不应该?\n", "4. **Pythonic 实现**:思考如何利用 Python 的特性(如动态类型、函数式特性、模块等)来更优雅地实现这些模式。\n", "\n", "不要试图一次性记住所有模式,而是要在实际开发中遇到类似问题时,能够识别出可能适用的模式,并查阅相关资料。最好的学习方式是通过实践和阅读优秀的代码。" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.10.12" } }, "nbformat": 4, "nbformat_minor": 5 }