Head First 适配器模式

10 阅读3分钟

一、定义

适配器模式:将一个类的接口,转换成客户期望的另一个接口。适配器让原本接口不兼容的类可以合作无间。
如果一段时间之后,我们改变了接口,适配器可以将改变的部分封装起来,客户就不必为了应对不同的接口而每次跟着修改。它是一种结构型设计模式。
适配器模式的核心概念包括目标接口(Target)、被适配者(Adaptee)、适配器(Adapter)。

  • Target: 目标接口,客户期望的接口。
  • Adaptee: 被适配者是需要被适配的类或接口,它与目标接口不兼容。
  • Adapter: 适配器作为中间件,通过继承或组合的方式将被适配者转换为目标接口。

适配器分为两种:对象适配器、类适配器。

对象适配器

现在来看看它的类图:

adapter.png

代码如下:

/**
 * Duck接口,它就是一个ITarget
 */
public interface Duck {

    void quack();

    void fly();
}
/**
 * 火鸡,他是一个被适配者Adaptee
 */
public interface Turkey {
    public void gobble();

    public void fly();
}
/**
 * 火鸡适配器:为了让Turkey充当Duck
 * 实现了Duck接口,并持有对Turkey的引用
 */
public class TurkeyAdapter implements Duck {
    private Turkey turkey;
    public TurkeyAdapter(Turkey turkey) {
        this.turkey = turkey;
    }

    @Override
    public void quack() {
        turkey.gobble();
    }

    @Override
    public void fly() {
        // 因为Duck飞的比Turkey要远。所以用Turkey的飞行距离的5倍长模仿Duck的飞行距离
        for (int i = 0; i < 5; i++) {
            turkey.fly();
        }
    }
}
/**
 * 测试类
 */
public class DuckTest {

    public static void main(String[] args) {
        // MallardDuck是Duck的一个实现类
        Duck mallardDuck = new MallardDuck();
        mallardDuck.quack();
        mallardDuck.fly();
        // WildTurkey是Turkey的一个实现类
        Turkey turkey = new WildTurkey();
        turkey.gobble();
        turkey.fly();

        Duck fakeDuck = new TurkeyAdapter(turkey);
        fakeDuck.quack();
        fakeDuck.fly();
    }
}

这个适配器模式具有良好的面向对象设计原则

  • 封装变化
  • 多用组合,少用继承
  • 对修改关闭,对扩展开放

这种做法的优点是:被适配者的任何子类,都可以搭配着适配器使用。

请留意:这个模式是把客户和接口绑定起来,而不是和实现绑定起来的。我们可以使用多个适配器,每一个都负责转换不同组的后台类。或者,也可以加上新的实现,只要他们遵守目标接口就可以。

类适配器

类适配器需要多重继承才能够实现,但在Java中是不可能的。但是当你在使用多重继承语言的时候,可以使用它。

现在来看看它的类图:

classAdapter.png

对象适配器和类适配器的比较

  • 对象适配器使用组合,不仅可以适配某个类,也可以适配该类的任何子类。而类适配器无法做到这一点,因为它只能够采用某个特定的被适配类,但是它不需要实现整个被适配者,必要的时候,也可以覆盖被适配者的行为。
  • 对象适配器更具有弹性,但类适配器实现起来更简单。

多种模式之间的对比

二、使用场景

在Spring Boot框架中,适配器模式有多个典型应用场景:

  1. Web请求处理‌:
    在Spring MVC中,DispatcherServlet是前端控制器,负责将请求分发给不同的处理器(handler),但是这些处理器的类型可能各不相同(如ControllerHandler、HttpRequestHandler等),它们的接口也不一致。为了统一处理这些不同类型的处理器,使用了适配器模式,引入HandlerAdapter接口来支持多种处理器类型(如@RequestMapping注解的控制器),通过适配器模式解耦请求处理逻辑。
  2. 数据转换‌:
    SpringBoot中的MessageConverter也是适配器模式的一个很好的例子。它负责将Http请求体转换给Java对象,或将Java对象转换为Http响应体。 SpringBoot提供了多种HttpMessageConverter接口的实现,如MappingJackson2HttpMessageConverter(处理JSON),MarshallingHttpMessageConverter(处理XML)等。通过适配器模式支持灵活的数据格式处理。