Middleman Patterns: Adapter / Proxy / Decorator

Yao Yao on September 8, 2021

我觉得用 Java 学 design pattern 有个问题就是:总是要有 interface / abstract class 介入,搞得整个 class hierarchy 非常复杂。其实我用 duck typing 的思路来看,Adapter、Proxy、Decorator 这三个模式的基本结构是一样的,都是 客户端中间商旧实现。你撇开 interface layer 看下面三个图,我只能说是完全一致!

+------+        +---------+        +------------+
| User |------->| Adapter |------->| RealObject |
+------+        +----+----+        +-----+------+
                     |                   |
                     v                   v
              +--------------+    +---------------+
              | NewInterface |    | RealInterface |
              +--------------+    +---------------+

xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

+------+         +-------+         +------------+
| User |-------->| Proxy |-------->| RealObject |
+------+         +---+---+         +-----+------+
                     |                   |
                     |                   v
                     |            +---------------+
                     +----------->| RealInterface |
                                  +---------------+

xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

+------+        +-----------+      +------------+
| User |------->| Decorator |----->| RealObject |
+------+        +-----+-----+      +-----+------+
                      |                  |
                      |                  v
                      |           +---------------+
                      +---------->| RealInterface |
                                  +---------------+

撇开 class hierarchy,这里先看看这三个 pattern 在功能上的区别:

  • Adapter: 接口修正
  • Proxy: 接口 Access Control
    • Proxy 并不会给 User 提供新的接口,也不会修改旧的业务逻辑 (behavior),它提供的都是 side effect
    • 比如 security / caching / lazy loading
  • Decorator: 维持原接口,但可能会修改业务逻辑 (behavior) 或者添加新的接口
    • “添加新的接口” 是可能的,比如我们可以把 Decorator 设计成 Interface which extends RealInterface 或者 abstract class

假设我们用 $\Lambda$ 表示 RealObject 提供的接口,用 $\Lambda’$ 表示 中间商 提供的接口,于是有:

\[\begin{aligned} \text{Adapter: } &\Lambda' = f(\Lambda), \, f \neq I \newline \text{Proxy: } &\Lambda' = I(\Lambda) = \Lambda \newline \text{Decorator: } &\Lambda' \supseteq \Lambda \end{aligned}\]

那至于 class hierarchy,我觉得这是 Java 的设计技巧,这里就不谈了。这三个 patterns 都有一个明显的特点是:中间商 holds an instance of RealObject,再次体现 “组合优先于继承”。

扩展:

  • 可以有 Proxy Chain (体现 Single Responsibility Principle,一个 Proxy 只做一方面的功能)
  • 同理可以有 Decorator Chain


blog comments powered by Disqus