Java设计模式之适配器模式详解

 更新时间:2023年09月14日 09:09:30   作者:十维豆脑  
这篇文章主要介绍了Java设计模式之适配器模式详解,适配器模式将一个类的接口转换成客户希望的另一个接口,Adapter模式使得原本由于接口不兼容而不能一起工作的哪些类可以一起工作,需要的朋友可以参考下

一、定义

适配器模式(Adapter Pattern):结构型模式之一,将一个类的接口转换成客户希望的另一个接口。

Adapter模式使得原本由于接口不兼容而不能一起工作的哪些类可以一起工作

二、UML类图

在这里插入图片描述

三、角色职责

  • 目标角色(Target):该角色定义把其他类转换为何种接口,也就是我们的期望接口。
  • 源角色(Adaptee):你想把谁转换成目标角色,这个“谁”就是源角色,它是已经存在的、运行良好的类或对象。
  • 适配器角色(Adapter):适配器模式的核心角色,其他两个角色都是已经存在的角色,而适配器角色是需要新建立的,它的职责非常简单:通过继承或是类关联的方式把源角色转换为目标角色。

四、代码实现

前言:举个栗子,我今天买了机票,飞到香港迪士尼去游玩,晚上回到了酒店,想给我的笔记本电脑充电,但这时我发现,香港的插座是英式三角插座,我的充电器插不进去。这时我们就可以使用适配器模式,进行适配。

  • 类适配器:适配器通过类来实现,以类来继承和实现接口的方式,来获取被适配类的信息并转换输出重写到适配接口。

中式插座(源角色 Adaptee)

@AllArgsConstructor
@Data
public class ChineseStandard {
    public String getChineseStandard() {
        return "中式插座";
    }
}

英式插座(目标角色 Target)

public interface BritishStandard {
    String getBritishStandard();
}

插座适配器(适配器角色 Adapter)

public class StandardAdapter extends ChineseStandard implements BritishStandard {
    @Override
    public String getBritishStandard() {
        return this.getChineseStandard();
    }
}

笔记本电脑(客户端 Client)

public class Notebook {
    public void charge(BritishStandard britishStandard) {
        if ("中式插座".equals(britishStandard.getBritishStandard())) {
            System.out.println("充电成功!");
        } else {
            System.out.println("充电失败!");
        }
    }
}

测试类

public class AdapterTest {
    public static void main(String[] args) {
        // 充电成功!
        new Notebook().charge(new StandardAdapter());
    }
}
  • 对象适配器:通过实例对象(构造器传递)来实现适配器,而不是再用继承,其余基本同类适配器。

我么们将插座适配器就行修改即可

@AllArgsConstructor
public class StandardAdapter implements BritishStandard {
    private ChineseStandard chineseStandard;
    @Override
    public String getBritishStandard() {
        return chineseStandard.getChineseStandard();
    }
}

测试类

public class AdapterTest {
    public static void main(String[] args) {
        // 充电成功!
        new Notebook().charge(new StandardAdapter(new ChineseStandard()));
    }
}

如果我们的源目标接口中还有一些其他我们不需要的方法,我们并不想去实现它,我们就可以将适配器作为一个抽象类,当我们实现适配器抽象类的时候只要重写我们需要的方法即可。这时候我们就用到了接口适配器。

  • 接口适配器:当不需要全部实现接口提供的方法时,可先设计一个抽象类实现接口,并为该接口中每个方法提供一个默认实现(空方法),那么该抽象类的子类可有选择地覆盖父类的某些方法来实现需求。

英式插座(目标角色 Target)

public interface BritishStandard {
    String getBritishStandard();
    String getTypeC();
    String getUSB();
}

插座适配器(适配器角色 Adapter)

@AllArgsConstructor
public abstract class StandardAdapter extends ChineseStandard implements BritishStandard {
    @Override
    public String getBritishStandard() {
        return null;
    }
    @Override
    public String getTypeC() {
        return null;
    }
    @Override
    public String getUSB() {
        return null;
    }
}

测试类

public class AdapterTest {
    public static void main(String[] args) {
        StandardAdapter standardAdapter= new StandardAdapter() {
            @Override
            public String getBritishStandard() {
                return new ChineseStandard().getChineseStandard();
            }
        };
        // 充电成功!
        new Notebook().charge(standardAdapter);
    }
}

五、源码分析

我们先来看一下Spring MVC的工作原理

在这里插入图片描述

  1. 浏览器发送请求到 控制器(DispatcherServlet)
  2. 控制器 根据请求地址, 到 HandlerMapping(处理器映射) 寻找对应的 Handler(处理器)
  3. HanldlerMapping 返回 找到的Handler
  4. DispatcherServlet 根据找到的Handler 找对应的HandlerAdaptor
  5. 执行对应的Handler方法
  6. Handler 将执行结果 和 要响应的视图名 封装成 ModelAndView 对象
  7. 控制器根据返回的 ViewName 找对应的ViewResolver (视图解析ViewResolver 将 Model 渲染到 View 中
  8. 将渲染结果 返回给控制器
  9. 最终将结果响应给客户端浏览器

可以看出Spring MVC中的适配主要执行Controller的请求处理方法。在Spring MVC中,DispatcherServlet作为用户,HandlerAdapter作为期望接口(目标角色 Target),Controller则为源角色(Adaptee)。Spring MVC中的Controller种类众多,不同类型的Controller通过不同的方法来对请求进行处理。 我们首先看一下HandlerAdapter接口

在这里插入图片描述

Spring MVC提供的Controler如下。

在这里插入图片描述

Spring MVC提供的Adapter如下。

在这里插入图片描述

该接口的每一个Controller都有一个适配器与之对应,这样的话,每自定义一个Controller需要定义一个实现HandlerAdapter的适配器。 我们进入DispatcherServlet类,查看是如何获得适配器的。

在这里插入图片描述

在这里插入图片描述

当Spring容器启动后,会将所有定义好的适配器对象存放在一个List集合中,当一个请求来临时,DispatcherServlet会通过 handler的类型找到对应适配器,并将该适配器对象返回给用户,然后就可以统一通过适配器的handle()方法来调用Controller中的用于处理请求的方法。通过适配器模式我们将所有的Controller统一交给 HandlerAdapter 处理,免去了写大量的 if-else 语句对 Controller进行判断,也更利于扩展新的Controller类型。

六、优缺点分析

类适配器 优点:可以根据需求重写Adaptee类的方法,使得Adapter的灵活性增强了。 缺点:有一定局限性。因为类适配器需要继承Target类,而Java是单继承机制,所以要求Adaptee类必须是接口。

对象适配器 优点:同一个Adapter可以把Adaptee类和他的子类都适配到目标接口。 缺点:需要重新定义Adaptee行为时,需要重新定义Adaptee的子类,并将适配器组合适配。

接口适配器 优点:可以灵活方便的选择性重写接口方法。 缺点:由于是匿名内部类的形式,所以不利于代码复用。

七、适用场景

  • 系统需要复用现有类,而该类的接口不符合系统的需求,可以使用适配器模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。
  • 多个组件功能类似,但接口不统一且可能会经常切换时,可使用适配器模式,使得客户端可以以统一的接口使用它们。

八、总结

适配器模式将现有接口转化为客户类所期望的接口,实现了对现有类的复用,它是一种使用频率非常高的设计模式,在软件开发中得以广泛应用,Spring等开源框架、驱动程序设计(如JDBC中的数据库驱动程序)中也都使用了适配器模式。

到此这篇关于Java设计模式之适配器模式详解的文章就介绍到这了,更多相关Java适配器模式内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Java设计模式之模板方法模式Template Method Pattern详解

    Java设计模式之模板方法模式Template Method Pattern详解

    在我们实际开发中,如果一个方法极其复杂时,如果我们将所有的逻辑写在一个方法中,那维护起来就很困难,要替换某些步骤时都要重新写,这样代码的扩展性就很差,当遇到这种情况就要考虑今天的主角——模板方法模式
    2022-11-11
  • 浅谈springboot 属性定义

    浅谈springboot 属性定义

    本篇文章主要介绍了浅谈springboot 属性定义,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-08-08
  • Java可变参数的应用小结

    Java可变参数的应用小结

    这篇文章主要介绍了Java可变参数的应用小结,实现同一个函数名,不同参数个数,实现的方法相同,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2023-10-10
  • 2021年最新Redis面试题汇总(4)

    2021年最新Redis面试题汇总(4)

    在程序员面试过程中redis相关的知识是常被问到的话题。这篇文章主要介绍了几道Redis面试题,整理一下分享给大家,感兴趣的小伙伴们可以参考一下
    2021-07-07
  • SpringBoot2.0集成WebSocket实现后台向前端推送信息

    SpringBoot2.0集成WebSocket实现后台向前端推送信息

    这篇文章主要介绍了SpringBoot2.0集成WebSocket实现后台向前端推送信息,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2021-01-01
  • Java Condition条件变量提高线程通信效率

    Java Condition条件变量提高线程通信效率

    这篇文章主要介绍了Java Condition条件变量提高线程通信效率,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-10-10
  • springboot使用单元测试实战

    springboot使用单元测试实战

    这篇文章主要介绍了springboot使用单元测试实战,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-09-09
  • java收集器Collector案例汇总

    java收集器Collector案例汇总

    这篇文章主要介绍了java收集器Collector案例汇总,Collectors作为Stream的collect方法的参数,Collector是一个接口,它是一个可变的汇聚操作,更多相关介绍,需要的朋友可以参考下
    2022-06-06
  • idea社区版如何设置vm options

    idea社区版如何设置vm options

    这篇文章主要介绍了idea社区版如何设置vm options问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2023-09-09
  • java抛出异常与finally实例解析

    java抛出异常与finally实例解析

    这篇文章主要介绍了java抛出异常与finally实例解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2019-10-10

最新评论