← 返回 Day 38 正文

Day 38 · 图解

Day 038 — 创建型设计模式:图解

Mermaid 与 ASCII 示意图,帮助理解单例、工厂、建造者模式


1️⃣ 单例模式(Singleton)

flowchart TB subgraph 多次获取 A1["s1 = Singleton()"] A2["s2 = Singleton()"] end A1 -->|__new__| C{_instance 存在?} A2 -->|__new__| C C -->|否| N["创建新实例<br/>_instance = new"] C -->|是| R["返回 _instance"] N --> R R --> S["s1 is s2 = True<br/>✅ 同一个实例"]
flowchart TB
    subgraph 多次获取
        A1["s1 = Singleton()"]
        A2["s2 = Singleton()"]
    end

    A1 -->|__new__| C{_instance 存在?}
    A2 -->|__new__| C

    C -->|否| N["创建新实例<br/>_instance = new"]
    C -->|是| R["返回 _instance"]

    N --> R
    R --> S["s1 is s2 = True<br/>✅ 同一个实例"]

三种实现方式对比

方式一:__new__ 方法
═══════════════════════
class Singleton:
    _instance = None

    def __new__(cls):
        if cls._instance is None:
            cls._instance = super().__new__(cls)
        return cls._instance

✅ 最 Pythonic
✅ 不多余实例化
✅ __init__ 仍会执行(需 _initialized 控制)


方式二:装饰器
═══════════════════════
@singleton
class Config:
    pass

✅ 不入侵类定义
✅ 灵活性高
❌ type(instance) 不会返回 Config


方式三:元类
═══════════════════════
class SingletonMeta(type):
    _instances = {}

    def __call__(cls, *args, **kwargs):
        ...

class Config(metaclass=SingletonMeta):
    pass

✅ type(instance) 正确
✅ 可继承
❌ 复杂度较高

2️⃣ 简单工厂模式

flowchart LR subgraph 客户端 C["notification =<br/>Factory.create('email')"] end subgraph 工厂 F["NotificationFactory"] F --> D{"type = ?"} end subgraph 产品 D -->|email| E["EmailNotification()"] D -->|sms| S["SMSNotification()"] D -->|push| P["PushNotification()"] end C --> F E --> R["notification.send('Hi!')"] S --> R P --> R
flowchart LR
    subgraph 客户端
        C["notification =<br/>Factory.create('email')"]
    end

    subgraph 工厂
        F["NotificationFactory"]
        F --> D{"type = ?"}
    end

    subgraph 产品
        D -->|email| E["EmailNotification()"]
        D -->|sms| S["SMSNotification()"]
        D -->|push| P["PushNotification()"]
    end

    C --> F
    E --> R["notification.send('Hi!')"]
    S --> R
    P --> R

工厂解耦

❌ 不使用工厂:                     ✅ 使用工厂:

def send_notification(channel, msg, to):
    if channel == "email":            def send_notification(channel, msg, to):
        notifier = EmailNotifier()        notifier = NotificationFactory.create(channel)
    elif channel == "sms":               notifier.send(msg, to)
        notifier = SMSNotifier()
    ...

    ← 创建逻辑混杂在业务逻辑中      ← 创建逻辑集中管理
    ← 新增渠道要改多处代码          ← 新增渠道只改工厂

3️⃣ 工厂方法模式

classDiagram class Application { <<abstract>> +new_document() str +create_document() Document* } class PDFApplication { +create_document() PDFDocument } class WordApplication { +create_document() WordDocument } class Document { <<interface>> +open() str +save() str } class PDFDocument { +open() str +save() str } class WordDocument { +open() str +save() str } Application <|-- PDFApplication : 继承 Application <|-- WordApplication : 继承 Document <|.. PDFDocument : 实现 Document <|.. WordDocument : 实现 PDFApplication --> PDFDocument : 创建 WordApplication --> WordDocument : 创建
classDiagram
    class Application {
        <<abstract>>
        +new_document() str
        +create_document() Document*
    }

    class PDFApplication {
        +create_document() PDFDocument
    }

    class WordApplication {
        +create_document() WordDocument
    }

    class Document {
        <<interface>>
        +open() str
        +save() str
    }

    class PDFDocument {
        +open() str
        +save() str
    }

    class WordDocument {
        +open() str
        +save() str
    }

    Application <|-- PDFApplication : 继承
    Application <|-- WordApplication : 继承
    Document <|.. PDFDocument : 实现
    Document <|.. WordDocument : 实现
    PDFApplication --> PDFDocument : 创建
    WordApplication --> WordDocument : 创建

演化过程

简单工厂:                    工厂方法:                    抽象工厂:
                                ┌─────────┐               ┌─────────────┐
┌──────────┐    Factory    ┌────┤App A    │   Document   │  WinFactory  │
│ Client   │───→ create()──→│    │create()─→ Doc A       │  ├─ WinButton │
└──────────┘               │    └─────────┘               │  └─ WinCheck  │
        │                  │                              │              │
        ▼                  │    ┌─────────┐               │  MacFactory  │
    ┌──────────┐           └────┤App B    │               │  ├─ MacButton│
    │ Product  │                │create()─→ Doc B         │  └─ MacCheck │
    └──────────┘                └─────────┘               └─────────────┘

    集中管理创建              创建逻辑分散到子类        创建一族相关产品
    扩展性差                  扩展性好                  产品族一致

4️⃣ 建造者模式(Builder)

flowchart TB subgraph 建造过程 B["Builder"] --> S1["size(12)"] S1 --> S2["crust('薄脆')"] S2 --> S3["sauce('番茄')"] S3 --> S4["cheese('马苏里拉')"] S4 --> S5["add_topping('培根')"] S5 --> S6["well_done()"] S6 --> S7["build() → Pizza"] end subgraph Director(可选) D["PizzaChef"] --> T1["make_margherita()"] D --> T2["make_pepperoni()"] T1 -->|使用 Builder| P1["玛格丽特披萨"] T2 -->|使用 Builder| P2["辣香肠披萨"] end S7 --> P["🍕 定制披萨"]
flowchart TB
    subgraph 建造过程
        B["Builder"] --> S1["size(12)"]
        S1 --> S2["crust('薄脆')"]
        S2 --> S3["sauce('番茄')"]
        S3 --> S4["cheese('马苏里拉')"]
        S4 --> S5["add_topping('培根')"]
        S5 --> S6["well_done()"]
        S6 --> S7["build() → Pizza"]
    end

    subgraph Director(可选)
        D["PizzaChef"] --> T1["make_margherita()"]
        D --> T2["make_pepperoni()"]
        T1 -->|使用 Builder| P1["玛格丽特披萨"]
        T2 -->|使用 Builder| P2["辣香肠披萨"]
    end

    S7 --> P["🍕 定制披萨"]

不使用 Builder vs 使用 Builder

❌ 不使用 Builder:                  ✅ 使用 Builder:

# 参数太多,顺序容易错              # 链式调用,名称明确
Pizza(12, "薄脆", "番茄",           Pizza.builder()
      True, "培根", 14)               .size(12)
                                      .crust("薄脆")
# 第 4 个参数 extra_cheese?           .sauce("番茄")
# 第 5 个参数 topping?                .add_topping("培根")
# 不读文档看不懂!                     .well_done()
                                      .build()
                                  ← 一目了然!
                                  ← 可选参数可省略

5️⃣ 原型模式(Prototype)

flowchart LR subgraph 原型 P["基础合同模板"] P --> V1["变量: {title, party_a, ...}"] end subgraph 克隆 C1["service = base.clone()"] C2["nba = base.clone()"] end subgraph 定制 C1 --> M1["修改变量: 服务合同"] C2 --> M2["修改变量: 球员合同"] end P --> C1 P --> C2
flowchart LR
    subgraph 原型
        P["基础合同模板"]
        P --> V1["变量: {title, party_a, ...}"]
    end

    subgraph 克隆
        C1["service = base.clone()"]
        C2["nba = base.clone()"]
    end

    subgraph 定制
        C1 --> M1["修改变量: 服务合同"]
        C2 --> M2["修改变量: 球员合同"]
    end

    P --> C1
    P --> C2

深拷贝 vs 浅拷贝

原型模式本质:克隆已有对象

浅拷贝 (copy.copy):               深拷贝 (copy.deepcopy):
═══════════════════               ═══════════════════════

对象 A ──→ 对象 A'                对象 A ──→ 对象 A'
  │            │                     │              │
  ├─ attr1     ├─ attr1              ├─ attr1       ├─ attr1
  └─ attr2 ──→ 共享引用              └─ attr2 ──→  复制新对象

✅ 快速                        ✅ 完全独立
⚠️ 共享引用可能产生副作用          ❌ 较慢

6️⃣ 连接池(对象池模式)

flowchart TB subgraph 连接池 POOL["ConnectionPool"] IDLE["空闲连接池: [Conn#1, Conn#2]"] IN_USE["使用中: {Conn#3}"] MAX["最大连接数: 5"] end T1["线程 1"] -->|acquire| POOL T2["线程 2"] -->|acquire| POOL POOL -->|复用空闲| T1 POOL -->|创建新连接| T2 T1 -->|release| POOL POOL -->|归还到空闲池| IDLE
flowchart TB
    subgraph 连接池
        POOL["ConnectionPool"]
        IDLE["空闲连接池: [Conn#1, Conn#2]"]
        IN_USE["使用中: {Conn#3}"]
        MAX["最大连接数: 5"]
    end

    T1["线程 1"] -->|acquire| POOL
    T2["线程 2"] -->|acquire| POOL
    POOL -->|复用空闲| T1
    POOL -->|创建新连接| T2

    T1 -->|release| POOL
    POOL -->|归还到空闲池| IDLE

7️⃣ 配置管理器设计

classDiagram class ConfigManager { -_config: dict -_frozen: bool -_readonly_keys: set -_listeners: list -_history: list +get(key, default) any +set(key, value) ConfigManager +freeze() ConfigManager +on_change(cb) ConfigManager +to_json() str +stats: dict } class ConfigBuilder { -_data: dict +set(key, value) ConfigBuilder +set_database() ConfigBuilder +set_redis() ConfigBuilder +set_app() ConfigBuilder +build() ConfigManager +build_and_freeze() ConfigManager } class ConfigFactory { +from_json_file(path) ConfigManager +from_json_str(str) ConfigManager +from_dict(dict) ConfigManager +from_defaults() ConfigManager } ConfigManager <.. ConfigBuilder : 建造 ConfigManager <.. ConfigFactory : 工厂创建
classDiagram
    class ConfigManager {
        -_config: dict
        -_frozen: bool
        -_readonly_keys: set
        -_listeners: list
        -_history: list
        +get(key, default) any
        +set(key, value) ConfigManager
        +freeze() ConfigManager
        +on_change(cb) ConfigManager
        +to_json() str
        +stats: dict
    }

    class ConfigBuilder {
        -_data: dict
        +set(key, value) ConfigBuilder
        +set_database() ConfigBuilder
        +set_redis() ConfigBuilder
        +set_app() ConfigBuilder
        +build() ConfigManager
        +build_and_freeze() ConfigManager
    }

    class ConfigFactory {
        +from_json_file(path) ConfigManager
        +from_json_str(str) ConfigManager
        +from_dict(dict) ConfigManager
        +from_defaults() ConfigManager
    }

    ConfigManager <.. ConfigBuilder : 建造
    ConfigManager <.. ConfigFactory : 工厂创建

设计模式在配置管理器中的应用

ConfigManager (单例)
  • __new__ 确保全局唯一实例
  • _initialized 确保仅初始化一次
  • 全局访问点:get() / set()

ConfigBuilder (建造者)
  • set_database() / set_app() 等预定义配置
  • 链式调用 self return
  • build() 创建 ConfigManager

ConfigFactory (工厂)
  • from_json_file() 从文件创建
  • from_dict() 从字典创建
  • from_defaults() 创建默认配置
  • 封装不同创建方式