设计模式-适配器模式

设计模式-适配器模式

适配器顾名思义,就是将原本不兼容的东西适配在一起,例如 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。
相关推荐
Zane19945 天前
一个 new 就能创建对象,为什么还要拆出单例、工厂、建造者、原型四种模式?
设计模式
怕浪猫6 天前
一行命令复刻爆款视频,我把 Hypit 从安装跑到了出片
人工智能·设计模式·程序员
Zane19946 天前
函数式编程里的函数,其实不是你天天写的那个函数——三大编程范式的边界在哪
设计模式
Zane19947 天前
策略模式现在该不该上?一次讲清楚过度设计和设计不足怎么找平衡
设计模式
她说..8 天前
常见设计模式-模板方法模式
java·spring·设计模式·springboot
xiaofeiyang1508 天前
第六章 · 桥接 — 三支毛笔,画出九种颜色
设计模式
Shadow(⊙o⊙)9 天前
OTOL设计模式 One Thread One Loop
服务器·网络·设计模式
sarasuki9 天前
如何让LLM 能在半夜偷偷打开网易云呢?
人工智能·设计模式·agent
小王师傅669 天前
【设计模式】装饰模式(四):框架源码实战——从 Java I/O 到 Spring 到 MyBatis
java·设计模式
执明wa9 天前
Android RecyclerView 多类型, 多种 Item
android·xml·开发语言·设计模式·android studio