带你了解不一眼的适配器模式

328 阅读4分钟

这是我参与2022首次更文挑战的第15天,活动详情查看:2022首次更文挑战

适配器模式

适配器模式概念

适配器模式(Adapter Pattern),也叫包装模式(Wrapper),主要功能是将一个类的接口变成客户端所希望的另外一个接口,适配器模式可以作为两个不兼容的接口之间的桥梁,从而使因接口不匹配而导致无法在一起工作的类能够一起工作,在类的过程中,适配器模式属于结构性模式。

从另外一个角度上来讲,如果存在一个系统,系统中存在两个接口A和B,客户只能访问A接口,但是如果系统中没有A对象,有B对象,但是客户无法访问B接口,所以需要一个适配器C类,将B类接口的内容转换为A接口,因此客户可以访问A接口从而得到B接口的内容。

在软件工程中,任何情况都可以通过增加一个中间层来进行解决。而适配器就是这个中间层。

适配器模式应用场景

  • Tomcat中如何将Request流转换成为标准的Request

  • 如何让tomcat使用CoyoteAdapte从而使用ServletRequest

  • Spring AOP中的AdvisorAdapter的前置适配器、后置适配器等方法

  • Spring MVC中经典的HandlerAdapter犯法的使用

适配器模式的通用写法

通常情况下适配器一般包含三种角色

  • 目标角色(Target):目标抽象类,

  • 源角色(Adaptee):存在于系统中,通过转换可以变成客户的需要的功能,但是接口不匹配的实例

  • 适配器角色(Adapter):将源角色转换为目标角色的中间类。

适配器模式各个角色的关系基本如下:客户端需要访问Target接口,但是Target接口没有一个实例符合客户需求,而Adaptee类符合客户需求,但是客户端不能直接访问Adaptee类,因此我们需要一个Adapter类将Adaptee类转换封装称为Target接口,从而提供给客户端使用。

具体代码实现如下

  • 源角色(Adaptee)
public class Adaptee {

    public int specificRequest() {
        return 225;
    }
}
  • 目标角色(Target)
public interface Target {
    int request();
}
  • 适配器角色(Adapter)
public class Adapter extends Adaptee implements Target {
    @Override
    public int request() {
        return super.specificRequest() / 10;
    }
}
  • UML结构图

image.png

通过上述代码可以知道Adapter就可以知道他具备了Target和Adaptee两个角色功能,就可以将两者相互的转化。

适配器模式的优缺点

优点

  • 将目标类和适配者类解耦,通过引入一个适配器类来重用现有的适配者类,而无须修改原有代码。
  • 增加了类的透明性和复用性,将具体的实现封装在适配者类中,对于客户端类来说是透明的,而且提高了适配者的复用性。
  • 灵活性和扩展性都非常好,通过使用配置文件,可以很方便地更换适配器,也可以在不修改原有代码的基础上增加新的适配器类,完全符合“开闭原则”。

缺点

  • 过多地使用适配器,会让系统非常零乱,不易整体进行把握。比如,明明看到调用的是 A 接口,其实内部被适配成了 B 接口的实现,一个系统如果太多出现这种情况,无异于一场灾难。因此如果不是很有必要,可以不使用适配器,而是直接对系统进行重构。
  • 由于 JAVA 至多继承一个类,所以至多只能适配一个适配者类,而且目标类必须是抽象类。增加代码的阅读难度,降低代码的可读性。

适配器模式和装饰器模式的区别

  • 相同点

    • 装饰器模式和适配器模式都是包装模式。
  • 不同点

    • 适配器模式没有层级关系,而装饰器模式存在层级关系

    • 装饰器模式是被装饰类和装饰类都实现同一个接口,适配器模式中适配类和被适配类没有必然的关系,

    • 适配器满足has-a的关系,而装饰器满是is-a的关系

    • 适配器注重于兼容和转换的功能,装饰器模式注重于扩展和覆盖的功能