标签 设计模式
 标签 适配器模式
 分类 技术文章
 分类 开源项目

死磕设计模式—适配器模式

前言(八问知识体系)

死磕设计模式-适配器模式

1.简介

  • 什么是适配器模式?

    • 1.将一个接口转换成客户希望的另一个接口,适配器模式使接口不兼容的那些类可以一起工作
    • 2.适配器模式既可以作为类结构型模式,也可以作为对象结构型模式
    • 3.适配器模式属于结构型模式
    • 4.适配器实现了统一管理,一个目标是适配接口对象多个适配器类
  • 适配器模式的优缺点?

    • 优点
      • 1.将目标类和适配者类解耦,通过引入一个适配器类来重用现有的适配者类,而无须修改原有代码
      • 2.增加了类的透明性和复用性,将具体的实现封装在适配者类中
      • 3.灵活性和扩展性都非常好,通过使用配置文件,可以很方便地更换适配器
      • 4.对象适配器模式还可以将不通的适配者适配到同一个目标接口上
    • 缺点
      • 1.过多的使用适配器类会让程序变得复杂
      • 2.类适配器模式还存在单继承的问题

2.类图

2.1.类适配器类图

image-20191103182240358

注意事项:Java是单继承机制,类适配器需要继承源类,这是一个缺点,同时源类的方法也在适配器类中暴漏出来,增加类使用的成本。

2.2.对象适配器类图

image-20191103184510712

PS:对象适配器模式更多是为类解决类适配器中的单继承问题,修改类实现方式,根据合成复用原则,使用组合的方式代替继承,同时使用的成本降低。

2.3.接口适配器类图

image-20191103192827142

PS:接口适配器就是重写接口中我们需要使用的方法,但是接口中会存在很多方法,所以我们会使用一个抽象类适配器采用默认空方法来实现接口,使用的时候采用内部类来覆写。

3.代码示例

3.1.类适配器

被适配类

@Slf4j
public class Adaptee {

    /**
     * outPut220V
     *
     * @return 220V电压
     * @description 输出220V的电压
     * @author luokangyuan
     * @date 2019/11/3 16:49
     * @version 1.0.0
     */
    public int outPut220V() {
        log.info("输出220V的电压");
        return 220;
    }
}

目标抽象接口

public interface Target {

    /**
     * outPut22V
     *
     * @description 输出22V的电压
     * @return 22V的电压
     * @author luokangyuan
     * @date 2019/11/3 16:50
     * @version 1.0.0
     */
    int outPut22V();
}

适配器类

public class Adapter extends Adaptee implements Target {

    @Override
    public int outPut22V() {
        // 1.得到需要适配的数据
        int i = outPut220V();
        // 2.适配转换操作
        int result = i / 10;
        // 返回适配后结果
        return result;
    }
}

客户端

public class Phone {
    /**
     * charging
     *
     * @param target : 适配接口
     * @description 手机充电方法
     * @author luokangyuan
     * @date 2019/11/3 17:00
     * @version 1.0.0
     */
    public void charging(Target target) {
        // 得到期望结果,开始后续操作
        int i = target.outPut22V();
        log.info("当前电压为{},开始充电操作", i);
    }
}

测试调用

public static void main(String[] args) {
    Phone phone = new Phone();
    phone.charging(new Adapter());
}

3.2.对象适配器

由于类适配器需要继承源类,由于Java是单继承,所以存在很大的局限性,所以出现类对象适配器,就是在适配器类中不再使用继承源类的方式,而是使用源类的实例来解决兼容性问题,即持有Src类,实现Dst类,完成适配。

根据合成复用原则,在系统中尽量使用关联关系来代替继承关系,对象适配器模式才是适配器模式中最常用的一种模式。

被适配类

public class Adaptee {

    /**
     * outPut220V
     *
     * @return 220V电压
     * @description 输出220V的电压
     * @author luokangyuan
     * @date 2019/11/3 16:49
     * @version 1.0.0
     */
    public int outPut220V() {
        log.info("输出220V的电压");
        return 220;
    }
}

目标抽象接口

public interface Target {

    /**
     * outPut22V
     *
     * @description 输出22V的电压
     * @return 22V的电压
     * @author luokangyuan
     * @date 2019/11/3 16:50
     * @version 1.0.0
     */
    int outPut22V();
}

适配器类

public class Adapter implements Target {

    private Adaptee adaptee;

    public Adapter(Adaptee adaptee) {
        this.adaptee = adaptee;
    }

    @Override
    public int outPut22V() {
        // 1.得到需要适配的数据
        int i = adaptee.outPut220V();
        // 2.适配转换操作
        int result = i / 10;
        // 返回适配后结果
        return result;
    }
}

客户端

public class Phone {

    /**
     * charging
     *
     * @param target : 适配接口
     * @description 手机充电方法
     * @author luokangyuan
     * @date 2019/11/3 17:00
     * @version 1.0.0
     */
    public void charging(Target target) {
        // 得到期望结果,开始后续操作
        int i = target.outPut22V();
        log.info("当前电压为{},开始充电操作", i);
    }
}

测试调用

public static void main(String[] args) {
    Phone phone = new Phone();
    phone.charging(new Adapter(new Adaptee()));
}

3.3.接口适配器

源接口

public interface IAdaptee {

    void method1();

    void method2();

    void method3();

    void method4();
}

抽象的接口适配器类

public  abstract  class AbsAdapter implements IAdaptee{

    @Override
    public void method1() {

    }

    @Override
    public void method2() {

    }

    @Override
    public void method3() {

    }

    @Override
    public void method4() {

    }
}

客户端

@Slf4j
public class Client {
    public static void main(String[] args) {
        new AbsAdapter() {
            @Override
            public void method1() {
                log.info("我只是使用了接口中的method1");
            }
        };
    }
}

4.总结

  • 适配器模式的使用场景?

    • 1.系统需要使用现有的类,而这些类的接口不符合系统的需要
  • 适配器模式的使用案例?

    • 1.SpringMvc中的HandlerAdapter使用了适配器模式
    • 2.java.util.Arrays#asList()也使用了适配器模式
    • 3.spring AOP中的AdvisorAdapter使用了适配器模式
    • 适配者类角色
目录