设计模式-适配器模式

设计模式-适配器模式

适配器顾名思义,就是将原本不兼容的东西适配在一起,例如 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。
相关推荐
楼田莉子21 分钟前
仿Muduo的高并发服务器:Channel模块与Poller模块
linux·服务器·c++·学习·设计模式
geovindu16 小时前
go: Strategy Pattern
开发语言·设计模式·golang·策略模式
嵌入式学习_force21 小时前
02_state
设计模式·蓝牙
qcx231 天前
Warp源码深度解析(七):Token预算策略——双轨计费、上下文溢出与摘要压缩
人工智能·设计模式·rust·wrap
Cosolar2 天前
提示词工程面试题系列 - Zero-Shot Prompting 和 Few-Shot Prompting 的核心区别是什么?
人工智能·设计模式·架构
geovindu2 天前
go:Template Method Pattern
开发语言·后端·设计模式·golang·模板方法模式
钝挫力PROGRAMER2 天前
贫血模型的改进
java·开发语言·设计模式·架构
qcx232 天前
Warp源码深度解析(二):自研GPU UI框架——WarpUI的ECH模式与渲染管线
人工智能·ui·设计模式·rust
qcx232 天前
Warp源码深度解析(三):Block-Based终端引擎——Grid模型、PTY与Shell Integration
人工智能·设计模式·架构·wrap
mounter6252 天前
Linux Kernel Design Patterns (Part 2):从经典链表到现代 XArray,拆解内核复杂数据结构的设计哲学
linux·数据结构·链表·设计模式·内存管理·kernel