zoukankan      html  css  js  c++  java
  • 设计模式:适配器模式(类适配器、对象适配器、接口适配器)


    适配器模式的工作原理:

    将一个类的接口转换为另一种接口,让原本接口不兼容的类可以兼容

    从用户的角度是看不到适配器的,是解耦的;用户调用的是适配器转化后的目标接口方法,适配器再调用被适配者的相关接口方法。(比如用户只用type-C,要的是这个口给出的5v电压,而适配器去插插孔),这样对于用户来说,只是目标和接口交互。


    一、类适配器模式


    类适配器会有一个 Adapter 类,通过继承 src(被适配者) 类,实现 dst(目标) 接口,完成从 src -> dst 的适配。

    这几个之间的关系:

    比如充电器是 Adapter , 220V 交流电是 src ,5V直流电是 dst。也就是说,目标是要插 dst ,但是只有 src 是源,src 需要被适配,src 是被适配者,适配器是 Adapter。

    如上类图所示:

    1. Phone 和接口 Dest 关联,为了的得到 5V 电压,和接口关联更加适合扩展,Dest就是我们的 dst;
    2. Src220V就是我们的src,提供220V的交流电,需要被适配;
    3. Adapter就是我们说的Adapter,完成把 src 转换为 dst 的功能,他实现了 dst 接口,继承了 src 类。
    /*
        被适配者
    */
    public class Src220V {
        public int output220V(){
            int src = 220;
            System.out.println("电压 = "  + src + "V");
            return src;
        }
    }
    
    /*
        目标dst,5V电压,是接口
    */
    public interface Dest5V {
         public int output5V();
    }
    
    /*
        类适配器Adapter,继承被适配类src,实现dst
    */
    public class Adapter extends Src220V implements Dest5V{
        @Override
        public int output5V() {
            //获取到源电压
            int src = output220V();
            //转成目标电压
            int dst = src / 44;
            return dst;
        }
    }
    
    /*
        手机直接依赖的是适配器Adapter,但是是通过Dest5V接口依赖的
    */
    public class Phone {
        //充电
        public void chongdian(Dest5V dest5V){
            //这里其实肯定是 5
            if (dest5V.output5V() == 5)
            System.out.println("电压为 5 V,可以正常充电");
        }
    }
    

    那么简单的测试就可以写一个客户端:

    public class Client {
        public static void main(String[] args) {
            System.out.println("=== 类适配器模式 ===");
            Phone phone = new Phone();
            phone.chongdian(new Adapter());
        }
    }
    

    总结:

    1. 因为 java 是单继承机制,所以类适配器 Adapter 需要继承 src ,算是一个缺点(一直强调尽量不要继承)。因为这个要求 dst 必须是接口,不能让 Adapter 同时继承两个类,有一定局限性;
    2. src 的方法都会在 Adapter中暴露出来,增加了使用成本;
    3. 优点:因为 Adapter 继承了 src 类,所以可以根据需求重写 src 类的方法,使得 Adapter 的灵活性增强。

    二、对象适配器模式


    对象适配器模式的基本思路和类适配器是相同的,只是将 Adapter 类稍作修改,不是继承 src 类,而是持有一个 src 的实例,解决兼容性的问题,即:持有 src 类,实现 dst 接口,完成 src -> dst 的适配。

    根据设计模式的第七个原则:合成复用原则,尽量不要继承,而用别的替代,这就是对象适配器改进的思路。

    和上一种 类适配器模式 一样,用手机充电的例子来修改代码,看一下类图的改变:

    src 不再是被继承,而是以一个实例的方式出现在 Adapter 里,其他地方做相应的改变即可。

    1. 被适配者 :不变;
    2. 目标dst : 不变;
    3. 适配器 Adapter:改变
    /*
        对象适配器Adapter,聚合一个被适配类src对象,实现dst
    */
    public class Adapter implements Dest5V{
        //聚合一个对象
        private Src220V src220V;
        //提供构造器
        public Adapter(Src220V src220V) {
            this.src220V = src220V;
        }
    
        @Override
        public int output5V() {
            int dst = 0;
            if (src220V != null){
                //获取到源电压
                int src = src220V.output220V();
                System.out.println("=== 使用对象适配器 ===");
                dst = src / 44;
            }
            return dst;
        }
    }
    
    1. 使用者Phone :不变;

    Client:响应改变,调用方式变了,需要 src 对象。

    public class Client {
        public static void main(String[] args) {
            System.out.println("=== 对象适配器模式 ===");
            Phone phone = new Phone();
            phone.chongdian(new Adapter(new Src220V()));
        }
    }
    

    总结:

    和类适配器是一种思想,不过根据合成复用原则,将 Adapter 必须继承 src 的局限性问题优化,变成聚合一个对象。


    三、接口适配器模式


    一些书也把接口适配器模式叫做 : 缺省适配器模式,或者适配器模式。

    当不需要全部实现接口提供的方法的时候,可以先设计一个抽象类来实现接口(都实现成一个空方法),那么接着抽象类的子类就可以有选择的覆盖父类的方法来实现需求。适用于一个接口不想使用其所有的方法的情况。

    对于上面的例子,可以不用直接实现 dst 这个接口,而是改成实现一个 AbstractAdapter,都实现成空方法,这样的话,继续让 Phone 依赖抽象类,就能用匿名内部类的方式重写某些方法。

    改动比较小,因此就不做代码示例了。


    四、适配器模式应用


    在 SpringMVC 框架里,源码的 HandlerAdapter 就使用了适配器模式。

  • 相关阅读:
    Linux 配置gitee
    Linux C errno出错处理
    Linux C进程时间:墙上时钟时间,用户CPU时间,系统CPU时钟时间
    编译错误: 对‘aio_read’未定义的引用
    Linux 异步IO(AIO)
    Linux getaddrinfo获得本机ip地址为何127.0.1.1?
    Linux 文件截断的几种方式
    如何创建守护进程?
    守护进程, 协同进程, 僵尸进程, 孤儿进程概念理解
    对线程安全, 可重入函数, 异步安全的理解
  • 原文地址:https://www.cnblogs.com/lifegoeson/p/13500465.html
Copyright © 2011-2022 走看看