一、定义

适配器模式(Adapter Pattern):结构型模式之一,将一个类的接口转换成客户希望的另一个接口。Adapter模式使得原本由于接口不兼容而不能一起工作的哪些类可以一起工作

二、UML类图

三、角色职责

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

四、代码实现

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

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

    中式插座(目标角色 Target)

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

    英式插座(源角色 Adaptee)

    public interface BritishStandard {String getBritishStandard();
    }
    

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

    public class StandardAdapter extends ChineseStandard implements BritishStandard {@Overridepublic 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;@Overridepublic String getBritishStandard() {return chineseStandard.getChineseStandard();}
    }
    

    测试类

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

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

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

    英式插座(源角色 Adaptee)

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

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

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

    测试类

    public class AdapterTest {public static void main(String[] args) {StandardAdapter standardAdapter= new StandardAdapter() {@Overridepublic 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中的数据库驱动程序)中也都使用了适配器模式。

适配器模式(Adapter Pattern)相关推荐

  1. 乐在其中设计模式(C#) - 适配器模式(Adapter Pattern)

    [索引页] [源码下载] 乐在其中设计模式(C#) - 适配器模式(Adapter Pattern) 作者:webabcd 介绍 将一个类的接口转换成客户希望的另外一个接口.Adapter模式使得原本 ...

  2. 【设计模式】适配器模式 Adapter Pattern

    适配器模式在软件开发界使用及其广泛,在工业界,现实中也是屡见不鲜.比如手机充电器,笔记本充电器,广播接收器,电视接收器等等.都是适配器. 适配器主要作用是让本来不兼容的两个事物兼容和谐的一起工作.比如 ...

  3. 极速理解设计模式系列:6.适配器模式(Adapter Pattern)

    四个角色:目标抽象类角色(Target).目标对象角色(Adapter).源对象角色(Adaptee).客户端角色(Client) 目标抽象类角色(Target):定义需要实现的目标接口 目标对象角色 ...

  4. 设计模式(七): 通过转接头来观察适配器模式(Adapter Pattern)

    在前面一篇博客中介绍了"命令模式"(Command Pattern),今天博客的主题是"适配器模式"(Adapter Pattern).适配器模式用处还是比较多 ...

  5. 适配器模式 Adapter Pattern

    适配器模式 适配器模式(Adapter Pattern)是作为两个不兼容的接口之间的桥梁.这种类型的设计模式属于结构型模式,它结合了两个独立接口的功能. 这种模式涉及到一个单一的类,该类负责加入独立的 ...

  6. php本地服务手机适配器,php适配器模式(adapter pattern)

    下午陪家人和小孩,晚上练起来. /* The adapter pattern allows the interface of an existing class to be used from ano ...

  7. C#设计模式——适配器模式(Adapter Pattern)

    一.概述 在软件开发中,常常会想要复用一个已经存在的组件,但该组件的接口却与我们的需要不相符,这时我们可以创建一个适配器,在需复用的组件的接口和我们需要的接口间进行转换,从而能够正常的使用需复用的组件 ...

  8. 设计模式之四:适配器模式(Adapter Pattern)

    在软件系统中,由于应用环境的变化,常常需要将"一些现存的对象"放在新的环境中应用,但是新环境要求的接口是这些现存对象所不满足的.如果能既能利用现有对象的良好实现,同时又能满足新的应 ...

  9. 使用C#实现适配器模式 (Adapter Pattern) 和外观模式 (Facade Pattern)

    本文的概念内容来自深入浅出设计模式一书 现实世界中的适配器(模式) 我带着一个国标插头的笔记本电脑, 来到欧洲, 想插入到欧洲标准的墙壁插座里面, 就需要用中间这个电源适配器. 面向对象的适配器 你有 ...

  10. 二十三种设计模式[6] - 适配器模式(Adapter Pattern)

    前言 适配器,属于类结构型模式.<设计模式 - 可复用的面向对象软件>一书中将之描述为" 将一个类的接口转换成客户希望的另一个接口,使得原本由于接口不兼容而不能一起工作的那些类可 ...

最新文章

  1. xStream完美转换XML、JSON
  2. 【分享】2019张小龙微信公开课要点整理
  3. Bugku—MISC题总结
  4. vue 生产word_nodejs(officegen)+vue(axios)在客户端导出word文档
  5. 图解CSS3----5-否定伪类选择器
  6. myeclipse下hibernate入门实例介绍
  7. python特性、属性以及私有化
  8. hadoop之文件管理基本操作
  9. (pytorch-深度学习系列)pytorch数据操作
  10. java outer关键字_java中的关键字
  11. 嗅觉计算机应用,sensonic计算机嗅觉分析仪
  12. 三道简单算法题(二)
  13. 安装McAfee 8.7i 提示错误1920怎么办?
  14. 【情感分析】基于Aspect的情感分析模型总结(PART IV)
  15. 使用Hex2Bin软件将Hex文件转Bin文件
  16. kafka集群搭建并验证(个人亲手搭建,真实有效)
  17. 金丹期前期:1.2、python语言-python的基本元素:变量及命名规则、数据类型及转换、运算符、输入输出
  18. 微信支付服务商模式(电商收付通)实现分账操作
  19. Nginx系列教材 (五)- 和Tomcat进行负载均衡
  20. NCCL下载及安装教程

热门文章

  1. 怎么用php跨域请求
  2. 小波与小波包、小波包分解与信号重构、小波包能量特征提取 暨 小波包分解后实现按频率大小分布重新排列(Matlab 程序详解)
  3. STS下载教程(include官网无法下载解决方案)
  4. matlab线性同余发生器,用MATLAB进行随机数模拟--线性同余法
  5. python爬虫网络库下载_Python3 DHT 网络磁力种子爬虫
  6. Java商城系统后端和小程序模板、毕业设计下载
  7. Leetcode学习成长记:天池leetcode基础训练营Task01数组
  8. LCD12864资料汇总(HDG12864F详细说明及驱动源码)
  9. MMDetection2.XX-Necks之FPN源码解析
  10. 计算机xp系统恢复以前设置,电脑xp系统怎么恢复出厂设置,xp系统怎么恢复出厂设置...