设计模式详解(七)——适配器模式

news/2024/10/21 11:33:29/

适配器模式简介

适配器模式定义
  将一个接口转换成客户希望的另一个接口,使接口不兼容的那些类可以一起工作,其别名为包装器(Wrapper)。简单的说就是用来做适配的,它将不兼容的接口转换为可兼容的接口,让原本由于接口不兼容而不能一起工作的类可以一起工作。
适配器模式既可以作为类结构型模式,也可以作为对象结构型模式。
在业务开发中我们会经常的需要做不同接口的兼容,比如需要把各个业务线的各种类型服务做统一包装,再对外提供接口进行使用。而这在我们平常的开发中也是非常常见的。
根据适配器类与适配者类的关系不同,适配器模式可分为对象适配器和类适配器两种,在对象适配器模式中,适配器与适配者之间是关联关系;在类适配器模式中,适配器与适配者之间是继承(或实现)关系。

适配器模式包含以下角色:
目标抽象类:Target,该角色把其他类转换为我们期望的接口,可以是一个抽象类或接口,也可以是具体类。定义Client使用的与特定领域相关的接口
被适配者: Adaptee ,原有的接口,也是希望被适配的接口。定义一个已经存在的接口,这个接口需要适配,需要适配别人(要适配者)
适配器: Adapter, 将被适配者和目标抽象类组合到一起的类。对Adaptee的接口与Target接口进行适配

适配器模式优缺点:
优点:
1、将目标类和适配者类解耦
2、增加了类的透明性和复用性,将具体的实现封装在适配者类中,对于客户端类来说是透明的,而且提高了适配者的复用性
3、灵活性和扩展性都非常好,符合开闭原则

缺点:
1、过多地使用适配器,会让系统非常零乱,不易整体进行把握。
2、 由于 JAVA 至多继承一个类,所以至多只能适配一个适配者类,而且目标类必须是抽象类。

使用场景
(1)系统需要使用现有的类,而此类的接口不符合需要。
(2)需要一个统一的输出接口,而输入类型不可预知。
(3)创建一个可以复用的类,使得该类可以与其他不相关的类或不可预见的类(协同工作。

适配器模式的实现
适配器模式有两种:“对象”适配器和“类”适配器。
对象适配器模式: 基本思路与类适配器模式相同, 只是将 Adapter适配器类修改, 不是继承 Adaptee被适配者, 而是拥有 Adaptee类的实例, 以解决兼容性的问题。
类适配器模式: Adapter适配器类, 继承 Adaptee被适配器类, 实现 Target目标类的接口, 完成适配。类适配器模式是通过让Adapter(适配器)实现Target(被适配者)的抽象接口,然后继承Adaptee(要适配者),具体适配过程是由我们的适配器的Resuest()方法中对Adaptee(要适配者)的SpecificRequest()方法进行适配,使得适配器的Request()方法返回我们需要的被适配者,供我们使用。

以下举一个类适配器的例子:
如:在生活中手机充电器, 需要将家用220V的交流电 转换为 5V的直流电后, 才能对手机充电

手机充电器 相当于 Adapter适配器
220V的交流电 相当于 Adaptee 被适配者
5V的直流电 相当于 Target目标

Adaptee被适配器类: 220V电压

/*** @author yyx*/
public class Adaptee {public int output220V() {System.out.println("正常220V电压");return 220;}
}

Target目标接口: 输出5V电压

/*** @author yyx*/
public interface Target {public int output5V();
}

Adapter适配器类: 将220V电压转换成 5V电压

/*** @author yyx*/
public class Adapter extends Adaptee implements Target {@Overridepublic int output5V() {// 获取到220V的电压int a = output220V();// 处理电压,转成5Vint b = a / 44;return b;}
}

手机实体类

/*** @author yyx*/
public class Phone {public void charging(Adapter voltage) {if (voltage.output5V() == 5) {System.out.println("电压适配为5V,可以充电");} else if (voltage.output5V() > 5) {System.out.println("电压大于5V,不能充电~");}}
}

测试Client:

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

运行结果如下所示:

类适配器模式
正常220V电压
电压适配为5V,可以充电

注意:
Java是单继承机制, Adapter类适配器需要继承 Adptee被适配者类, 导致 Target目标必须是接口, 有一定的局限性 (继承, 破坏了类的封装性, 父类对于子类来说是透明的, 且耦合度高)
由于继承 Adptee被适配者类, 所以可以根据需求重写 Adptee被适配者类的方法, 是的Adapter的灵活性增强了

** 对象适配器的例子:**
对象适配器模式: 基本思路与类适配器模式相同, 只是将 Adapter适配器类修改, 不是继承 Adaptee被适配者, 而是拥有 Adaptee类的实例, 以解决兼容性的问题.

修改Adapter适配器类, 将继承Adaptee类, 修改成拥有Adaptee类的成员属性
Adapter适配器类

/*** @author yyx*/
//public class Adapter extends Adaptee implements Target {
//    @Override
//    public int output5V() {
//        // 获取到220V的电压
//        int a = output220V();
//        // 处理电压,转成5V
//        int b = a / 44;
//        return b;
//    }
//}public class Adapter implements Target {private Adaptee adaptee;public Adapter() {}public Adapter(Adaptee adaptee) {this.adaptee = adaptee;}@Overridepublic int output5V() {int dst = 0;if (adaptee != null) {int src = adaptee.output220V();System.out.println("使用对象适配器进行适配");dst = src / 44;System.out.println("适配完成,输出电压为:" + dst);}return dst;}
}

测试Client:

/*** @author yyx*/
public class Client {
//    public static void main(String[] args) {
//        System.out.println("类适配器模式");
//        Phone phone = new Phone();
//        phone.charging(new Adapter());
//    }public static void main(String[] args) {System.out.println("对象适配器模式");Phone phone = new Phone();phone.charging(new Adapter(new Adaptee()));}
}

运行结果如下所示:

对象适配器模式
正常220V电压
使用对象适配器进行适配
适配完成,输出电压为:5
电压适配为5V,可以充电

注意:对象适配器模式相比于类适配器模式会更加灵活一些,我们的Adaptee是通过构造器传入的,这样可以更方便我们代码的扩展(多态),而且类适配器如果Target不是一个接口,也是一个类的话,Java中是不支持多继承的。

总而言之:
适配器模式的用意是要改变源的接口,以便于目标接口相容。缺省适配的用意稍有不同,它是为了方便建立一个不平庸的适配器类而提供的一种平庸实现。建议尽量使用对象的适配器模式,多用合成/聚合、少用继承。
总结:
1.从用户的角度看不到被适配者,是解耦的
2.用户直接调用适配器转化出来的目标接口方法,适配器再调用被适配者的相关接口方法
3.适配器实现了用户收到反馈结果,感觉只是和目标接口交互
4.适配器将一个对象包装起来用以改变其接口。
5.当需要使用一个现有的类而其接口并不符合你的需求时,可以使用适配器。
6.实现一个适配器可能会花一番功夫,可能也会毫不费力,原因是有其目标接口的大小与复杂度决定。


以上代码下载请点击该链接:https://github.com/Yarrow052/Java-package.git


http://www.ppmy.cn/news/351231.html

相关文章

计算机图像处理—HOG 特征提取算法

一、实验介绍 1. 实验内容 本实验将学习HOG 特征提取算法。 2. 实验要点 HOG 算法HOG 算法有效的原因创建 HOG 描述符HOG 描述符中的元素数量可视化 HOG 描述符理解直方图 3. 实验环境 Python 3.6.6numpymatplotlibcv2copy 二、实验步骤 简介 正如在 ORB 算法中看到的…

翻译的技巧

400字左右的文章中划出5个句子, 30分钟内将其翻译成中文,分值10分。文章的题材大多是有关政治、经济、文化、教育、科普以及社会生活,议论文为主,说明文为辅,结构严谨,逻辑性强,长难句较多。不仅…

App移动端测试 —— Monkey的日志

Monkey的日志对于分析脚本的执行情况十分必要。 Monkey 日志由以下几部分组成: 测试命令信息:随机种子 seed、运行次数、可运行应用列表、各事件百分比。” 正文内容从这里开始(可直接省略,亦可配图说明)。 01—Mon…

mac下部署和访问 Kubernetes 仪表板(Dashboard)

简介 Dashboard 是基于网页的 Kubernetes 用户界面。 你可以使用 Dashboard 将容器应用部署到 Kubernetes 集群中,也可以对容器应用排错,还能管理集群资源。 你可以使用 Dashboard 获取运行在集群中的应用的概览信息,也可以创建或者修改 Kub…

oracle中的正则表达式

^ 使表达式定位至一行的开头 $ 使表达式定位至一行的末尾 * 匹配 0 次或更多次 ? 匹配 0 次或 1 次 匹配 1 次或更多次 {m} 正好匹配 m 次 {m,} 至少匹配 m 次 {m, n} 至少匹配 m 次但不超过 n 次 [:alpha:] 字母字符 [:lower:] 小写字母字符 [:upper:] 大写字母字符 [:digit…

【C/C++】初始化列表

1.简介 C初始化列表是一种用于在对象构造过程中初始化成员变量的语法结构。它使用在构造函数的参数列表后面使用冒号(:)来指定成员变量的初始化值。 2. 用法 以下是初始化列表的基本语法形式: ConstructorName(argument list) : member1(…

[C语言实现]数据结构之《关于我转生成队列这档事》

🥰作者: FlashRider 🌏专栏: 数据结构 🍖知识概要:详解队列的概念、顺序队列和链式队列的优点和缺点,以及代码实现。 目录 什么是队列? 选择什么结构来实现队列? 链式队列的实现 队列的结构…

二分法(java)

目录 一、简介:二、模板:三、例题: 一、简介: 二分法是一种常见的算法思想,也称为二分查找、折半查找。其核心思想是通过将目标数据与有序的数据序列进行比较,每次查找都将数据序列一分为二,确定…