设计模式-适配器模式

设计模式-适配器模式

适配器顾名思义,就是将原本不兼容的东西适配在一起,例如 MacBook 只有 type-c 接口,而我们需要一个网口插网线,就会买个转接器,这其实就是适配器的思想,通过协议转换将原本不兼容的东西变得兼容。

适配器是一种思想,可大可小。上述的例子其实就很小,有一个这样的系统,A系统市场很大,根深蒂固,对外宣称接口定义不会根据你的需求进行更改,B系统是另一个领域的市场大哥,也不会按你的需求进行更改,现在AB系统需要通信,又不想定制修改,就可以由其他厂商开发一个新项目,起适配器的作用,转换 AB 之间的协议。

如果你对 Web 容器有了解,知道 Tomcat、Jetty,它们其实都是遵循 Servlet 规范设计的,而 Servlet 规范要求传入的请求都是 ServletRequest,因此 Tomcat 的连接器中有一个 Adapter 组件,就是将譬如 HttpRequest 等转为 ServletRequest。

适配器实现

适配器模式一般有两种实现方式,基于类的和基于对象的。类适配器基于继承实现,而对象适配器基于组合实现。

基于类的实现
java 复制代码
public class Adaptee {
    public void function1() {
        System.out.println("fun1");
    }

    public void function2() {
        System.out.println("fun2");
    }

    public void functionC() {
        System.out.println("funC");
    }
}

public class Adapter extends Adaptee implements ITarget {
    @Override
    public void functionA() {
        super.function1();
    }

    @Override
    public void functionB() {
        super.function2();
    }
}

public interface ITarget {
    void functionA();

    void functionB();

    void functionC();
}

public class Main {
    public static void main(String[] args) {
        ITarget target = new Adapter();
        target.functionA();
        target.functionC();
    }
}

Adapter 类继承 Adaptee 实现了 ITarget 接口,这样可以无需重写 functionC 方法,因为二者命名和实现是一致的,适合大部分方法还是兼容,只是少量需要重写的情况。

基于对象的实现
java 复制代码
public class Adaptee {

    public void function1() {
        System.out.println("fun1");
    }

    public void function2() {
        System.out.println("fun2");
    }

    public void function3() {
        System.out.println("fun3");
    }

}

public class Adapter implements ITarget {

    private Adaptee adaptee;

    @Override
    public void functionA() {
        adaptee.function1();
    }

    @Override
    public void functionB() {
        adaptee.function2();
    }

    @Override
    public void functionC() {
        adaptee.function3();
    }
}

public interface ITarget {

    void functionA();

    void functionB();

    void functionC();

}

基于组合的实现其实与我们说的用组合代替继承的思想一致,委托给真正的执行者执行。

至于基于对象和基于类的适配器该如何选择,取决于以下方面:

  • 如果 Adaptee 接口并不多,那两种实现方式都可以
  • 如果 Adaptee 接口数量很多且与 ITarget 不一致,都需要重写,那就选择基于对象的组合实现
  • 如果 Adaptee 接口数量很多且与 ITarget 基本一致,那么就可以选择基于类的,但是要考虑接口的稳定性,如果频繁变更,那完全可以也选择组合实现
使用场景
  • 封装有缺陷的设计,例如原来的方法有漏洞但是其他系统不影响,就可以针对这个系统单独再封装一次进行适配
  • 统一多个类的接口设计,例如有三个过滤方法ABC,A的参数是 String,B的也是 String, C的是 String,String(第一个参数是要过滤的关键词,第二个是替换为什么,例如***),就可以使用适配器兼容
  • 替代依赖的外部系统,B站有一个视频利用 etcd 代替 redis,使得 redisTemplate 操作的中间件无感切换为 etcd,设计模式-适配器模式
  • 兼容老版本接口,老版本的接口依然保留,但实现切换为新版本的操作。JDK1.0 中包含一个遍历集合容器的类 Enumeration。JDK2.0 对这个类进行了重构,将它改名为 Iterator 类,并且对它的代码实现做了优化。为了做到兼容使用低版本 JDK 的老代码,暂时保留 Enumeration 类,并将其实现替换为直接调用 Itertor。
相关推荐
心若自由何处是束缚11 小时前
适配器模式:从原理到实战的完整指南
设计模式·适配器模式
是2的10次方啊15 小时前
设计模式与生活⑮:看到哪儿了,得有个地方替你记着
设计模式
2601_967979121 天前
设计模式 - 访问者模式
设计模式·访问者模式·应用场景·对象结构·操作分离
是2的10次方啊2 天前
设计模式与生活⑭:一栋楼,共用一份热
设计模式
是2的10次方啊3 天前
设计模式与生活⑬:你坐几号线,谁来运营是另一回事
设计模式
Tt有了t4 天前
设计模式速查
java·python·设计模式
一条Go4 天前
四个进程,一把锁:Alioth 的告警评测为什么不需要消息队列
后端·设计模式·架构
一缕82年的清风4 天前
被中产唾弃的“十元快剪”,藏着最狠的极客工程学
人工智能·设计模式
是2的10次方啊4 天前
设计模式与生活⑫:周报又到手,别从空白开始
设计模式
拆房老料4 天前
DeepSeek Super-agent 架构解析:从单任务 Agent 到持续运行的任务系统
人工智能·设计模式·系统架构