• 设计模式-适配器模式(Adapter)


    一、适配器模式概述

    1.1 什么是适配器模式

    适配器模式(Adapter Pattern)是一种结构型设计模式,它主要用于解决两个不兼容的接口之间的问题。这种模式通过结合两个独立接口的功能,使原本不能一起工作的那些类可以一起工作。

    适配器模式涉及到一个单一的类,这个类负责将独立的或不兼容的接口功能整合到一起。举个例子,读卡器就是作为内存卡和笔记本之间的适配器。我们先把内存卡插入读卡器,再把读卡器插入笔记本,然后就可以通过笔记本来读取内存卡的内容了。

    适配器模式也被称为Wrapper(包装器),因为它主要是将目标类用一个新类包装一下,即在客户端与目标类之间加了一层。这解决了现存的类提供的接口与我们系统的接口不兼容,而我们还不能修改现存类的问题。

    1.2 简单实现适配器模式

    首先,我们定义一个目标接口Target:

    public interface Target {
        void request();
    }
    
    • 1
    • 2
    • 3

    然后,我们创建一个实现了Target接口的具体类ConcreteTarget:

    public class ConcreteTarget implements Target {
        @Override
        public void request() {
            System.out.println("ConcreteTarget 的 request 方法被调用");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    接下来,我们创建一个需要适配的接口Adaptee:

    public interface Adaptee {
        void specificRequest();
    }
    
    • 1
    • 2
    • 3

    然后,我们创建一个实现了Adaptee接口的具体类ConcreteAdaptee:

    public class ConcreteAdaptee implements Adaptee {
        @Override
        public void specificRequest() {
            System.out.println("ConcreteAdaptee 的 specificRequest 方法被调用");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    现在,我们需要创建一个适配器类Adapter,它也实现了Target接口,并包含一个Adaptee类型的成员变量。在Adapter类的request方法中,我们将调用Adaptee的specificRequest方法:

    public class Adapter implements Target {
        private Adaptee adaptee;
    
        public Adapter(Adaptee adaptee) {
            this.adaptee = adaptee;
        }
    
        @Override
        public void request() {
            System.out.println("Adapter 的 request 方法被调用");
            adaptee.specificRequest();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    最后,我们在客户端代码中使用适配器模式:

    public class Client {
        public static void main(String[] args) {
            Adaptee adaptee = new ConcreteAdaptee();
            Target target = new Adapter(adaptee);
            target.request();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    运行客户端代码,输出结果如下:

    Adapter 的 request 方法被调用
    ConcreteAdaptee 的 specificRequest 方法被调用
    
    • 1
    • 2

    1.3 使用适配器模式注意事项

    在使用适配器模式时,需要注意以下几点:

    • 1、适配器模式主要解决现有接口无法改变的问题。也就是说,适配器不是在详细设计阶段添加的,而是在解决正在运行的项目问题时使用的。

    • 2、由于Java是单继承机制,类适配器需要继承src类,这一点算是一个缺点。因为这意味着目标类必须是接口,这就给设计带来了一定的局限性。

    • 3、src类的方法在Adapter中都会暴露出来,这可能会增加使用的成本。

    • 4、尽管适配器模式可以解决一些兼容性问题,但如果没有合理使用,可能会导致系统复杂性增加。因此,在使用时需要权衡利弊,尽量避免过度使用。

    • 5、当适配器的任何方法被调用时,它会将参数转换为合适的格式,然后将调用定向到其封装对象中的一个或多个方法。因此,正确实现适配器模式对于保证代码的稳定运行至关重要。

    二、适配器模式的用途

    适配器模式主要应用于解决系统需要使用现有类,但这些类的接口不符合系统的需要,即接口不兼容的问题。以下是一些具体的应用场景:

    • 1、系统需要使用现有的类,而此类的接口不符合系统的需要,即接口不兼容。例如,你可能需要将一个现有的类(如某个第三方库中的类)与你自己的代码一起使用,但这个现有类的接口与你所需要的接口不匹配。这时,你可以创建一个适配器类,将现有的类适配到你所需要的接口。

    • 2、如果你想建立一个可以重复使用的类,用于与一些彼此之间没有太大关联的一些类,包括一些可能在将来引进的类一起工作。例如,你可能需要开发一个通用的数据处理模块,该模块应该能够处理多种不同类型的数据源(如数据库、文件、网络等)。这时,你可以创建一个适配器类,将不同的数据源适配到你的数据处理模块所期望的接口。

    • 3、需要一个统一的输出接口,而输入端的类型不可预知。例如,你可能需要编写一个函数,该函数接受一个对象作为参数,并调用该对象的某个方法。但是,该方法的参数类型和返回值类型可能有很多种可能性。这时,你可以创建一个适配器类,将不同的参数类型和返回值类型适配到你所需要的接口。

    • 4、当需增加客户端与目标类之间的抽象层以控制对目标类的访问。这种情况下,适配器模式可以为客户端提供一个与目标类更为友好的接口。

    三、实现适配器模式的方式

    3.1 继承适配器模式(Inheritance Adapter)

    通过继承原有的类,实现适配器功能。这种方式适用于接口不兼容的情况,但需要修改原有类的代码。

    public class Adaptee {
        public void specificRequest() {
            System.out.println("Adaptee specific request");
        }
    }
    
    public class Adapter extends Adaptee {
        @Override
        public void request() {
            super.specificRequest();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    3.2 组合适配器模式(Composition Adapter)

    通过组合的方式实现适配器功能。这种方式适用于接口不兼容的情况,且不需要修改原有类的代码。

    public interface Target {
        void request();
    }
    
    public class Adaptee {
        public void specificRequest() {
            System.out.println("Adaptee specific request");
        }
    }
    
    public class Adapter implements Target {
        private Adaptee adaptee;
    
        public Adapter(Adaptee adaptee) {
            this.adaptee = adaptee;
        }
    
        @Override
        public void request() {
            adaptee.specificRequest();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    3.3 装饰器适配器模式(Decorator Adapter)

    通过装饰器模式实现适配器功能。这种方式适用于接口不兼容的情况,且不需要修改原有类的代码。

    public interface Target {
        void request();
    }
    
    public class Adaptee {
        public void specificRequest() {
            System.out.println("Adaptee specific request");
        }
    }
    
    public class Adapter implements Target {
        private Adaptee adaptee;
    
        public Adapter(Adaptee adaptee) {
            this.adaptee = adaptee;
        }
    
        @Override
        public void request() {
            adaptee.specificRequest();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    3.4 代理适配器模式(Proxy Adapter)

    通过代理模式实现适配器功能。这种方式适用于接口不兼容的情况,且不需要修改原有类的代码。

    public interface Target {
        void request();
    }
    
    public class Adaptee {
        public void specificRequest() {
            System.out.println("Adaptee specific request");
        }
    }
    
    public class Adapter implements Target {
        private Adaptee adaptee;
    
        public Adapter(Adaptee adaptee) {
            this.adaptee = adaptee;
        }
    
        @Override
        public void request() {
            adaptee.specificRequest();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
  • 相关阅读:
    前几天,小灰去贵州了
    【文末送书】十大排序算法C++代码实现
    docker 命令
    服了,攻城狮的酒后真言竟然是这些?
    Window 2016 + VMWare +Thingworx 8.5 安装总结
    小程序2.
    uni-app接入mPaas扫码
    大厂面试题-JVM为什么使用元空间替换了永久代?
    嵌套循环基础练习题
    websocket flv 客户端解封包
  • 原文地址:https://blog.csdn.net/miaoyl1234/article/details/134245834