设计模式-Adapter

131 阅读3分钟

结构型模式

组成

在某些场景下,我们想复用一个已有的类,但是该类与我们要使用它的场景中其他类不兼容,这个时候,我们可以使用Adapter 模式。

Adapter 模式有两种实现方式:类继承、对象组合,UML 如下所示:

图1. 类适配器使用多重继承对两个(接口)进行匹配

图2. 对象适配器依赖于对象组合

Adapter 模式一般由以下组成:

1、Client--客户端,调用 Target 对象

2、Target--提供方法,与 Client 进行协同

3、Adaptee-- 已经存在的类,想复用的对象类

4、Adapter-- 对Adaptee与Tagrget进行适配

Client 直接调用的是 Target 类,但是我们想调用的是 Adaptee 的方法,这个时候,我们就需要对Target进行适配。因为Target是无法修改的,所以我们只能让Adapter继承或实现Target类,然后在Adapter类中把请求转发给Adaptee的方法。

在图1中,Adapter 继承了 Target类,并实现了Adaptee接口,然后在 Adapter 的方法(request 方法继承自 Target)中调用继承自 Adaptee 的方法。

在图2中,Adapter继承了Target类,但是持有了Adaptee对象的引用,然后在Target的方法中调用了Adaptee 对象的方法。

选择权衡

类适配器

  • Adapter 类继承了 Adaptee 类,当想要适配 Adaptee 的其他子类时,无法实现
  • 仅仅引入一个对象,不需要额外的对 Adaptee 的引用

对象适配器:

  • 允许 Adapter 与 Adaptee 的任意子类适配
  • 需要额外一个对 Adaptee 对象的引用

变和不变

不变的是Client 和 Target,Client 永远是调用Target去实现逻辑;

变化的是“Adaptee”,Target可以引用不同的Adaptee 来具体实现Client 的请求;

为了适配 Target和Adaptee,需要一个 Adapter。

应用场景

一个已经存在的类(Target),我们想复用它,但是它不满足我们的要求,我们又没办法修改它,这个时候我们可以使用适配器模式从中产生我们需要的类(Adaptee)。

示例代码

在 Spring Session 框架中,就使用了 Adapter模式,比如 HttpSessionAdapter类作为 HttpSession 和 Session 的适配器,类的定义如下:

class HttpSessionAdapter<S extends Session> implements HttpSession {

    private static final Log logger = LogFactory.getLog(HttpSessionAdapter.class);

    private S session;

    private final ServletContext servletContext;

    private boolean invalidated;

    private boolean old;

    HttpSessionAdapter(S session, ServletContext servletContext) {
        if (session == null) {
            throw new IllegalArgumentException("session cannot be null");
        }
        if (servletContext == null) {
            throw new IllegalArgumentException("servletContext cannot be null");
        }
        this.session = session;
        this.servletContext = servletContext;
    }
}

Spring session 想复用已有的 HttpSession 对象,且已有的 HttpSession 对象不满足需求(比如定时过期等),Spring session 就创建了满足自己需求的接口 Session,然后把两者适配起来:

1、使用HttpSessionAdapter来适配这两个接口:HttpSessionAdapter实现了HttpSession,然后持有一个Session实例

2、把HttpSessionAdapter作为HttpSession实例注入到容器中

3、每次调用HttpSession相关方法时,HttpSessionAdapter实际调用的是Session的方法

优点和缺点

小结

感觉适配器模式更多的场景是:我们依赖了一个框架(外部环境),框架中的类 X 不满足我们的要求,我们可以通过继承这个类来重写它的某些方法,也可以自定义 Adaptee 然后用 Adapter 来适配 X 和 Adaptee。