设计模式结构型——适配器模式

适配器模式是一种设计模式,用于解决接口不兼容问题,允许不同类协同工作。它分为类适配器、对象适配器和接口适配器三种,各自有优缺点。类适配器通过继承实现,对象适配器采用组合,接口适配器利用抽象类提供默认实现。适配器模式能解耦合,提高复用性,但也可能使系统更复杂,影响可维护性。
摘要由CSDN通过智能技术生成

目录

什么是适配器模式

适配器模式的实现

适配器模式角色

类适配器类图

类适配器代码实现

对象适配器类图

对象适配器代码实现

接口适配器类图

接口适配器代码实现

适配器模式的特点

优点

缺点

注意事项

使用场景

和其他模式的对比


什么是适配器模式

        适配器模式(Adapter)其别名为包装器模式(Wrapper),将一个类的接口适配成用户所期待的。一个适配允许通常因为接口不兼容而不能在一起工作的类工作在一起,做法是将类自己的接口包裹在一个已存在的类中。

        在适配器模式中,通过增加一个新的适配器类来解决接口不兼容的问题,使得原本没有任何关系的类可以协同工作。

        根据适配器类与适配者类的关系不同,适配器模式可分为对象适配器、类适配器、接口适配器三种。

        举例说明:当你需要给手机充电,但是墙上只有三叉口的插座,这时候,就需要用到三叉口插排,插排上有二叉口,这是就能给手机充电了,插排就起到了一个适配器的作用。

类适配器

释义:类适配器提供一个实现该接口的类,并且扩展已有的类,通过创建子类来实现适配。
优点:可以根据需求重写Adaptee类的方法,使得Adapter的灵活性增强了。
缺点:有一定局限性。因为类适配器需要继承Target类,而Java是单继承机制,所以要求Adaptee类必须是接口。

对象适配器

释义:对象适配器”通过组合除了满足“用户期待接口”还降低了代码间的不良耦合。在工作中推荐使用“对象适配”。
优点:同一个Adapter可以把Adaptee类和他的子类都适配到目标接口。
缺点:需要重新定义Adaptee行为时,需要重新定义Adaptee的子类,并将适配器组合适配。

接口适配器

释义:接口适配器借助中间抽象类空实现目标接口所有方法,子类选择性重写,可以减少实现不必要方法。
优点:可以灵活方便的选择性重写接口方法。
缺点:由于是匿名内部类的形式,所以不利于代码复用。

适配器模式的实现

适配器模式角色

  1. 目标角色(Target):该角色定义把其他类转换为何种接口,也就是我们的期望接口,可以是一个抽象类或接口,也可以是具体类。
  2. 源角色(Adaptee):想把谁转换成目标角色,是希望被适配的接口,这个“谁”就是源角色,它是已经存在的、运行良好的类或对象。
  3. 适配器角色(Adapter):适配器模式的核心角色,其他两个角色都是已经存在的角色,而适配器角色是需要新建立的,它的职责非常简单:通过继承或是类关联的方式把源角色转换为目标角色(将被适配者和目标抽象类组合到一起,把源角色转换为目标角色)。

类适配器类图

 从上图可以看出,Adaptee类并没有operation2()方法,而客户端则期待这个方法。为使客户端能够使用Adaptee类,需要提供一个包装(Wrapper)类Adapter。这个包装类包装了一个Adaptee的实例,从而此包装类能够把Adaptee的API与Target类的API衔接起来。Adapter与Adaptee是委派关系,这决定了适配器模式是对象的。

类适配器代码实现

/**
 * @author Evan Walker 昂焱数据: https://www.ayshuju.com
 * @version 1.0
 * @desc 类适配器
 * @date 2023/06/07 14:39:18
 */
class Adaptee{//源角色
    public void operation1(){
        System.out.println("这是原来的类,里面存在operation1");
    }
}

interface Target{//目标接口
    void operation1();
    void operation2();
}
class Adapter extends Adaptee implements Target{//适配器类
    @Override
    public void operation2() {
        System.out.println("这是接口中的方法。");
    }
}

public class Test {
    public static void main(String[] args) {
        Target adapter = new Adapter();
        adapter.operation1();
        adapter.operation2();
    }
}

运行结果如下:

对象适配器类图

 从上图可以看出,Adaptee类并没有operation2()方法,而客户端则期待这个方法。为使客户端能够使用Adaptee类,需要提供一个包装(Wrapper)类Adapter。这个包装类包装了一个Adaptee的实例,从而此包装类能够把Adaptee的API与Target类的API衔接起来。Adapter与Adaptee是委派关系,这决定了适配器模式是对象的。

对象适配器代码实现

/**
 * @author Evan Walker 昂焱数据: https://www.ayshuju.com
 * @version 1.0
 * @desc 对象适配器
 * @date 2023/06/07 14:39:18
 */

/**
 * 目标接口
 */
interface Target {
    void operation1();
    void operation2();
}

/**
 * 源角色
 */
class Adaptee {
    public void operation1() {
        System.out.println("这是原来的类,里面存在operation1");
    }
}

/**
 * 适配器角色
 */
class Adapter implements Target{

    private Adaptee adaptee;

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

    /**
     * 源类Adaptee有方法operation1
     * 因此适配器类直接委派即可
     */
    @Override
    public void operation1() {
        this.adaptee.operation1();
    }

    /**
     * 源类Adaptee没有方法operation2
     * 因此由适配器类需要补充此方法
     */
    @Override
    public void operation2() {
        System.out.println("这是接口中的方法。");

    }
}

public class Test {
    public static void main(String[] args) {
        Target adapter = new Adapter(new Adaptee());
        adapter.operation1();
        adapter.operation2();
    }
}

运行结果如下:

接口适配器类图

接口适配(Default Adapter)模式为一个接口提供缺省实现,这样子类型可以从这个缺省实现进行扩展,而不必从原有接口进行扩展。

接口适配器代码实现

/**
 * @author Evan Walker 昂焱数据: https://www.ayshuju.com
 * @version 1.0
 * @desc
 * @date 2023/06/08 16:27:14
 */

/**
 * 目标接口
 */
interface Target{
    void operation1();
    void operation2();
    void operation3();
}

/**
 * 定义一个抽象类,来选择需要重写的类
 */
abstract class abstractAdaptee implements Target{
    @Override
    public void operation1(){
        System.out.println("默认实现operation1");
    }
    @Override
    public abstract void operation2();//这个方法必须由子类来重写
    @Override
    public void operation3(){
        System.out.println("默认实现operation3");
    }
}
/**
 * 定义一个类来继承abstractAdaptee类
 * 通过接口和抽象类的结合,我们在子类中可以选择性的去实现那些抽象方法
 */
class Adapter extends abstractAdaptee{
    @Override
    public void operation2() {
        System.out.println("子类必须重写这个方法");
    }
}

public class Test {
    public static void main(String[] args) {
        Target adapter = new Adapter();
        adapter.operation1();
        adapter.operation2();
        adapter.operation3();
    }
}

运行结果如下:

适配器模式的特点

优点

  1. 将目标类和适配者类解耦,让任何两个没有关联的类一起运行。通过引入一个适配器类来重用现有的适配者类,无须修改原有结构。
  2. 提高了类的透明度和复用性。将具体的业务实现过程封装在适配者类中,对于客户端类而言是透明的,而且提高了适配者类的复用性,同一个适配者类可以在多个不同的系统中复用。
  3. 灵活性和扩展性都非常好,可通过使用配置文件方便更换适配器,也可不改原有代码,新增的适配器类,符合“开闭原则”。

缺点

  1. 过多地使用适配器,会让系统非常零乱,会让系统看起来很复杂,不易维护(因为需要从全局考虑),不易整体进行把握。
  2. 增加代码的阅读难度 

注意事项

  1. 适配器模式最好在详细设计不要考虑它,它不是为了解决还处在开发阶段的问题,而是解决正在服役的项目问题。

使用场景

  1. 有动机地修改一个正常运行的系统的接口,可以考虑使用适配器模式。
  2. 多个组件功能类似,但接口不统一且可能会经常切换时,可使用适配器模式,使得客户端可以以统一的接口使用它们。
  3. 系统需要复用现有类,而该类的接口不符合系统的需求,导致无法直接去访问,可使用适配器模式,就能间接去访问这个类中的方法。

和其他模式的对比

  1. 适配器模式和装饰者模式:装饰者模式是对以前的类进行进一步的封装与增强,目的是一层一层的增加功能,而适配器模式主要是为了协调多个调用者不同的调用方式而设计出来的。
  2. 适配器模式和外观模式:都是对现有类的封装,外观模式定义了新的接口,适配器则是复用已有的接口,适配器是两个接口协调工作,而外观模式则是为了别人使用的方便,提供了一个比较易用的接口

更多消息资讯,请访问昂焱数据(https://www.ayshuju.com)

  • 3
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值