← 返回 Day 39 正文

Day 39 · 图解

Day 39 — 结构型模式图解

本文档使用 Mermaid 图和 ASCII 图展示三种核心结构型模式的工作原理和关系。


一、三种模式全景对比

┌─────────────────────────────────────────────────────────────────────┐
│                    结构型设计模式全景图                               │
├─────────────────────────────────────────────────────────────────────┤
│                                                                     │
│  适配器模式           代理模式                装饰器模式               │
│  ┌────────┐         ┌────────┐            ┌────────┐               │
│  │客户端  │         │客户端  │            │客户端  │               │
│  └───┬────┘         └───┬────┘            └───┬────┘               │
│      │                  │                     │                    │
│      ▼                  ▼                     ▼                    │
│  ┌────────┐         ┌────────┐            ┌────────┐               │
│  │适配器  │         │ 代理   │            │装饰器A │               │
│  └───┬────┘         └───┬────┘            └───┬────┘               │
│      │ 委派             │ 委派                 │ 委派               │
│      ▼                  ▼                     ▼                    │
│  ┌────────┐         ┌────────┐            ┌────────┐               │
│  │第三方  │         │真实对象│            │装饰器B │               │
│  └────────┘         └────────┘            └───┬────┘               │
│  ↑ 改接口            ↑ 控访问                   │ 委派              │
│                                               ▼                    │
│                                           ┌────────┐              │
│                                           │真实对象│              │
│                                           └────────┘              │
│                                           ↑ 层层叠加功能           │
└─────────────────────────────────────────────────────────────────────┘

二、适配器模式(Adapter)

类图

classDiagram class Target { <<interface>> +request() string } class Adapter { -adaptee: Adaptee +request() string } class Adaptee { +specificRequest() string } class Client { +process(target: Target) } Target <|.. Adapter : implements Adapter o--> Adaptee : adaptee Client --> Target : uses note for Adapter "将 specificRequest()\n包装为 request()" note for Adaptee "接口不兼容\n但功能可用"
classDiagram
    class Target {
        <<interface>>
        +request() string
    }
    class Adapter {
        -adaptee: Adaptee
        +request() string
    }
    class Adaptee {
        +specificRequest() string
    }
    class Client {
        +process(target: Target)
    }
    Target <|.. Adapter : implements
    Adapter o--> Adaptee : adaptee
    Client --> Target : uses
    
    note for Adapter "将 specificRequest()\n包装为 request()"
    note for Adaptee "接口不兼容\n但功能可用"

数据流

客户端 (期望 XML)        适配器                   第三方 API (JSON)
      │                    │                          │
      │ 1. get_xml_data()  │                          │
      │───────────────────▶│                          │
      │                    │ 2. fetch_weather()       │
      │                    │─────────────────────────▶│
      │                    │ 3. 返回 JSON             │
      │                    │◀─────────────────────────│
      │                    │ 4. 将 JSON 转为 XML       │
      │                    │    (遍历键值对构建 XML)   │
      │ 5. 返回 XML       │                          │
      │◀───────────────────│                          │
      ▼                    ▼                          ▼
   ✅ 收到 XML           适配器完全透明              第三方完全不知

三、代理模式(Proxy)

类图

classDiagram class Subject { <<interface>> +request() } class RealSubject { +request() } class Proxy { -realSubject: RealSubject +request() +checkAccess() +logAccess() } Subject <|.. RealSubject : implements Subject <|.. Proxy : implements Proxy o--> RealSubject : realSubject note for Proxy "控制访问\n延迟加载\n记录日志"
classDiagram
    class Subject {
        <<interface>>
        +request()
    }
    class RealSubject {
        +request()
    }
    class Proxy {
        -realSubject: RealSubject
        +request()
        +checkAccess()
        +logAccess()
    }
    Subject <|.. RealSubject : implements
    Subject <|.. Proxy : implements
    Proxy o--> RealSubject : realSubject
    
    note for Proxy "控制访问\n延迟加载\n记录日志"

访问流程(虚拟代理 + 保护代理)

    客户端                   代理                     真实对象
      │                      │                          │
      │ request()            │                          │
      │─────────────────────▶│                          │
      │                      │                          │
      │                    ┌──┴──┐                      │
      │                    │ 权限检查 │                    │
      │                    └──┬──┘                      │
      │                      │                          │
      │                  ┌────┴────┐                    │
      │                  │ 无权限?  │                    │
      │                  │  → ❌   │                    │
      │                  │ 有权限?  │                    │
      │                  │  → 继续  │                    │
      │                  └────┬────┘                    │
      │                      │                          │
      │                 ┌────┴─────┐                    │
      │                 │ 日志记录  │                    │
      │                 └────┬─────┘                    │
      │                      │                          │
      │                 ┌────┴─────┐                    │
      │                 │ 延迟创建  │                    │
      │                 │ (如未创建)│                    │
      │                 └────┬─────┘                    │
      │                      │                          │
      │                      │ request()                │
      │                      │─────────────────────────▶│
      │                      │                          │
      │                      │◀─────────────────────────│
      │                      │    处理结果              │
      │◀─────────────────────│                          │
      ▼                      ▼                          ▼

缓存代理流程图

                 ┌─────────────────────┐
                 │     客户端请求       │
                 └──────────┬──────────┘
                            │
                            ▼
                 ┌─────────────────────┐
                 │  缓存代理:查缓存    │
                 └──────────┬──────────┘
                            │
                ┌───────────┴───────────┐
                │                       │
            ┌───▼───┐             ┌─────▼─────┐
            │命中缓存│             │未命中缓存  │
            └───┬───┘             └─────┬─────┘
                │                       │
                ▼                       ▼
         ┌──────────┐          ┌────────────────┐
         │是否过期?  │          │ 查真实服务     │
         └──┬───────┘          │ (数据库/API)   │
            │                  └───────┬────────┘
        ┌───┴───┐                      │
        │       │                      ▼
    ┌───▼──┐ ┌──▼───┐          ┌──────────────┐
    │ 未过期│ │ 已过期 │          │ 写入缓存     │
    │ ✅   │ │  删除 │          │ (带TTL)      │
    └───┬──┘ └──────┘          └──────┬───────┘
        │                              │
        ▼                              ▼
    ┌──────────────────────────────────────┐
    │          返回结果给客户端             │
    └──────────────────────────────────────┘

四、装饰器模式(Decorator)

类图

classDiagram class Component { <<interface>> +cost() float +description() string } class Coffee { +cost() float +description() string } class Decorator { -component: Component +cost() float +description() string } class MilkDecorator { +cost() float +description() string } class SugarDecorator { +cost() float +description() string } class WhippedCreamDecorator { +cost() float +description() string } Component <|.. Coffee : implements Component <|.. Decorator : implements Decorator o--> Component : component Decorator <|-- MilkDecorator Decorator <|-- SugarDecorator Decorator <|-- WhippedCreamDecorator note for Coffee "基础咖啡\ncost=22" note for MilkDecorator "+5元" note for SugarDecorator "+3元"
classDiagram
    class Component {
        <<interface>>
        +cost() float
        +description() string
    }
    class Coffee {
        +cost() float
        +description() string
    }
    class Decorator {
        -component: Component
        +cost() float
        +description() string
    }
    class MilkDecorator {
        +cost() float
        +description() string
    }
    class SugarDecorator {
        +cost() float
        +description() string
    }
    class WhippedCreamDecorator {
        +cost() float
        +description() string
    }
    
    Component <|.. Coffee : implements
    Component <|.. Decorator : implements
    Decorator o--> Component : component
    Decorator <|-- MilkDecorator
    Decorator <|-- SugarDecorator
    Decorator <|-- WhippedCreamDecorator
    
    note for Coffee "基础咖啡\ncost=22"
    note for MilkDecorator "+5元"
    note for SugarDecorator "+3元"

层层装饰过程

基础咖啡 (22元)
┌──────────────────────────────────────┐
│              美式咖啡                  │
│  cost = 22.0                          │
│  description = "美式咖啡"              │
└──────────────────────────────────────┘
                  │
    加奶泡 (MilkDecorator)
                  │
                  ▼
┌──────────────────────────────────────┐
│           MilkDecorator               │
│  component = 美式咖啡                  │
│  cost = 22.0 + 5.0 = 27.0            │
│  description = "美式咖啡 + 奶泡"       │
└──────────────────────────────────────┘
                  │
    加焦糖 (CaramelDecorator)
                  │
                  ▼
┌──────────────────────────────────────┐
│         CaramelDecorator              │
│  component = MilkDecorator            │
│  cost = 27.0 + 3.0 = 30.0            │
│  description = "美式咖啡 + 奶泡 + 焦糖"│
└──────────────────────────────────────┘
                  │
    客户端拿到最终对象
                  ▼
          总价: 30.0 元
        描述: "美式咖啡 + 奶泡 + 焦糖"

调用栈

client.cost() 的调用链:

1. CaramelDecorator.cost()
   │
   ├─ 3.0 + self.component.cost()
   │        │
   │        └─ MilkDecorator.cost()
   │             │
   │             ├─ 5.0 + self.component.cost()
   │             │        │
   │             │        └─ Coffee.cost() = 22.0
   │             │
   │             └─ 返回 27.0
   │
   └─ 返回 30.0 ✅

五、三种模式的关系

适配器 vs 代理

适配器:让 A 和 B 能对话
  A ──▶ 适配器(改接口) ──▶ B

代理:替 A 控制对 B 的访问
  A ──▶ 代理(控访问) ──▶ B

关键区别:适配器改变接口,代理保持接口不变。
适配器解决的是"不兼容",代理解决的是"控制"。

代理 vs 装饰器

代理:控制对对象的访问
  A ──▶ 代理(加控制) ──▶ 对象

装饰器:给对象动态加功能
  A ──▶ 装饰器A(加功能) ──▶ 装饰器B(加功能) ──▶ 对象

关键区别:
- 代理通常只包装一层,目的是控制访问
- 装饰器可以多层堆叠,目的是扩展功能
- 代理通常创建真实对象(延迟加载),装饰器不创建对象

三者的代码结构对比

python
# 适配器模式
class Adapter(Target):
    def __init__(self, adaptee):
        self._adaptee = adaptee  # 不兼容的接口
    def request(self):            # 实现目标接口
        return self._adaptee.specific_request()

# 代理模式
class Proxy(Subject):
    def __init__(self, real_subject=None):
        self._real = real_subject  # 可延迟创建
    def request(self):
        if self.check_access():    # 访问控制
            self._real.request()

# 装饰器模式
class Decorator(Component):
    def __init__(self, component):
        self._component = component  # 已兼容的对象
    def operation(self):
        self._before()               # 前处理
        result = self._component.operation()  # 委派
        self._after()                # 后处理
        return result

记住三句话: - 适配器 ≈ 翻译官(把英语翻译成中文) - 代理 ≈ 前台/秘书(帮你挡掉不必要的干扰) - 装饰器 ≈ 咖啡加料(基础咖啡 + 奶 + 糖 + 奶油∞)