惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

P
Privacy International News Feed
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
Jina AI
Jina AI
T
Tailwind CSS Blog
WordPress大学
WordPress大学
Scott Helme
Scott Helme
C
Cybersecurity and Infrastructure Security Agency CISA
博客园 - Franky
C
CERT Recently Published Vulnerability Notes
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
雷峰网
雷峰网
Schneier on Security
Schneier on Security
博客园 - 聂微东
T
Tor Project blog
Hugging Face - Blog
Hugging Face - Blog
博客园 - 司徒正美
AI
AI
T
Troy Hunt's Blog
Security Latest
Security Latest
T
The Blog of Author Tim Ferriss
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
C
Check Point Blog
T
Threat Research - Cisco Blogs
W
WeLiveSecurity
V
Vulnerabilities – Threatpost
Recorded Future
Recorded Future
Recent Commits to openclaw:main
Recent Commits to openclaw:main
Cisco Talos Blog
Cisco Talos Blog
C
CXSECURITY Database RSS Feed - CXSecurity.com
Cloudbric
Cloudbric
J
Java Code Geeks
罗磊的独立博客
C
Cyber Attacks, Cyber Crime and Cyber Security
aimingoo的专栏
aimingoo的专栏
L
LangChain Blog
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
P
Privacy & Cybersecurity Law Blog
Google DeepMind News
Google DeepMind News
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
L
Lohrmann on Cybersecurity
I
InfoQ
MongoDB | Blog
MongoDB | Blog
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
The GitHub Blog
The GitHub Blog
The Hacker News
The Hacker News
H
Help Net Security
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
P
Proofpoint News Feed
N
News and Events Feed by Topic

Java技术经验分享

生产故障处理SOP分享 | Java技术经验分享 系统稳定性建设实践总结【转载】 | Java技术经验分享 valine访问leancloud国际版异常,评论失效修复 | Java技术经验分享 匆匆忙忙的2021 | Java技术经验分享 聊一下换工作 | Java技术经验分享 IoT系列(2):WIFI设备常见配网方案介绍 | Java技术经验分享 IoT系列(1):什么是物联网 | Java技术经验分享 Java8特性2 - StreamApi | Java技术经验分享 Java8特性1 - lambda表达式&函数式接口 | Java技术经验分享 设计模式(4)-建造者模式 | Java技术经验分享 设计模式(3)-原型模式与浅拷贝和深拷贝 | Java技术经验分享 设计模式(2)-工厂模式图文介绍 | Java技术经验分享 设计模式(1)-带你了解3类8种单例模式 | Java技术经验分享 Java时间处理5---Java8中时区相关类库介绍 | Java技术经验分享 Java时间处理4---Java8中LocalDate、LocalTime、LocalDateTime介绍 | Java技术经验分享 Java时间处理3---Java8中Instant、Duration、Period、Clock介绍 | Java技术经验分享 一些有意思的问答 | Java技术经验分享 Nacos系列博客说明 | Java技术经验分享 菜鸡程序员的2019年度总结 | Java技术经验分享 Java中“附近的人”实现方案讨论及代码实现 | Java技术经验分享 Java时间处理2----时区TimeZone类方法探究(Java8以前) | Java技术经验分享 Java时间处理1----Date和Calendar方法探究(Java8以前) | Java技术经验分享 FastJson中JSONString、JavaBean、JSONObject、JSONArray的转换关系及API示例 | Java技术经验分享 2019.11软考软件设计师归来心得体会及复习备考指南 | Java技术经验分享 你还没用过“约定式提交”吗?那你赶紧来补补知识吧 | Java技术经验分享 教你如何看懂UML中的类图及类图中的关系 | Java技术经验分享 设计模式总览 | Java技术经验分享 萌新入门Github请看这里,学不会远程教 | Java技术经验分享 Hexo的工作原理探究 | Java技术经验分享 Hexo-theme-butterfly修改调整记录教程 | Java技术经验分享 排序8:基数排序 | Java技术经验分享 排序7:归并排序 | Java技术经验分享 排序6:快速排序 | Java技术经验分享 排序5:冒泡排序 | Java技术经验分享 排序4:堆排序 | Java技术经验分享 排序3:选择排序 | Java技术经验分享 排序2:希尔排序 | Java技术经验分享 排序1:直接插入排序 | Java技术经验分享 推荐一款博客一文多发的良心工具OpenWrite | Java技术经验分享 近期学习计划 | Java技术经验分享 Nacos(九):Nacos集群部署和遇到的问题 | Java技术经验分享 Nacos(八):Nacos持久化 | Java技术经验分享 Nacos(七):Nacos共享配置 | Java技术经验分享 Nacos(六):多环境下如何“管理”及“隔离”配置和服务 | Java技术经验分享 Nacos(五):多环境下如何“读取”Nacos中相应的配置 | Java技术经验分享 Nacos(四):SpringCloud项目中接入Nacos作为配置中心 | Java技术经验分享 Nacos(三):Nacos与OpenFeign的对接使用 | Java技术经验分享 Nacos(二):SpringCloud项目中接入Nacos作为注册中心 | Java技术经验分享 Nacos(一):Nacos介绍 | Java技术经验分享 20190719小组分享 | Java技术经验分享 Java中equals和HashCode方法的分析 | Java技术经验分享 Java中==和equals方法的分析 | Java技术经验分享 Java中的自动拆装箱、装箱缓存 | Java技术经验分享 About-blog | Java技术经验分享 Java中的编译、反编译和反编译工具全家桶分享 | Java技术经验分享 finalize()的生命周期(执行过程) | Java技术经验分享 Java关键字之final、finally与finalize方法 | Java技术经验分享 Java中重写、重载 | Java技术经验分享 Java中面向对象的三大特征:继承、封装、多态 | Java技术经验分享 DockerFile介绍 | Java技术经验分享 Docker环境下安装Gitlab | Java技术经验分享 Docker中私有仓库的搭建流程 | Java技术经验分享 Centos7下两种方式安装Docker-CE | Java技术经验分享 Vert.x创建一个Http服务 | Java技术经验分享 Vert.x创建TCP服务端及客户端 | Java技术经验分享 Vert.x Core(二)- Event Bus(事件总线) | Java技术经验分享 Vert.x-Core(一)- 基础篇 | Java技术经验分享 SpringBoot项目中实现国际化 | Java技术经验分享 Vert.x介绍 | Java技术经验分享 毕设选题项目本地运行环境搭建教程 | Java技术经验分享 Jupyter Notebooks的安装和使用介绍 | Java技术经验分享 算法笔试题:1元,5元,10元,20元,50元、100元面值人民币组合给定x元的问题 | Java技术经验分享 Quartz学习总结 | Java技术经验分享 SpringBoot2.x集成Redis | Java技术经验分享 SpringBoot2.x集成MongoDB | Java技术经验分享 [SpringCloud学习] - 浅谈微服务架构 | Java技术经验分享 基于hexo和coding免费搭建个人博客网站 | Java技术经验分享 Hello World | Java技术经验分享
设计模式(5)-适配器模式 | Java技术经验分享
文章作者: LarsCheng · 2020-10-11 · via Java技术经验分享

定义

适配器模式:将一个类的接口转换为调用方希望的另一个接口,使得原本不兼容的接口变得可兼容共同工作

举一个生活中的例子来解释适配器模式如下:

角色和分类

适配器模式种分为3大角色

  • 目标接口:当前系统业务所期待的接口,抽象类或者接口
  • 适配者类:要被适配的类,原本不兼容的类
  • 适配器类:一个转换器,通过继承或引用适配者对象,把适配者接口转换成目标接口,使得客户按照目标接口的格式访问适配者

适配器模式分为3种:

  • 类适配器模式
  • 对象适配器模式
  • 接口适配器模式

下面分别对他们进行介绍

类适配器模式

手机充电器为例来介绍类适配器模式:充电器将220V交流电转换为5V直流电这一过程。其中的角色如下

  • 输出5v电压:目标接口,兼容手机充电
  • 电源插座:适配者类,要被适配,不适合手机直接充电
  • 手机充电器:适配器类,将220V不可用的电压转换为手机可用的充电电压

简易的类图结构如下:

代码实现

目标接口,定义一个将220转换为5v的接口,作为一个标准,提供给各个厂商的电源适配器使用

1
2
3
public interface IOutput5V {
int output5v();
}

被适配类,电源插座,提供220v的直流电,不能被手机直接使用

1
2
3
4
5
6
7
public class Output220V {
public int output220(){
int src = 220;
System.out.println("电源输出电压:220V");
return src;
}
}

适配器类,继承了被适配类,实现目标接口具体的适配转换逻辑

1
2
3
4
5
6
7
8
9
10
public class Adapter220To5 extends Output220V implements IOutput5V {
@Override
public int output5v() {
int src = output220();

int dts = src / 44;
System.out.println("充电器适配后电压:" + dts);
return dts;
}
}

以上便完成了主要的角色实现,编写手机的充电方法进行测试

1
2
3
4
5
6
7
8
9
10
11
12
13
public class Phone {

public void charging(IOutput5V iOutput5V){
if (iOutput5V.output5v()==5){
System.out.println("电压5v,开始充电");
}else {
System.err.println("电压不符,无法充电");
}
}
public static void main(String[] args) {
new Phone().charging(new Adapter220To5());
}
}

运行后输出结果如下:

1
2
3
电源输出电压:220V
充电器适配后电压:5V
电压5v,开始充电

类适配器模式说明

适配器的实现过程中是继承了被适配类同时实现目标接口的方式,这样的原因是受Java单继承的限制,所以在类适配器模式下算是一个小小的缺点,使用继承大大的增加了适配器的复杂度。

对象适配器模式

基本思路和类的适配器模式相同,只是将Adapter类作修改,不是继承待适配类,而是持有待适配类的实例,以解决兼容性的问题。 即:持有待适配类,实现目标接口,完成兼容性适配

依然按照上文的场景和角色只有适配器类的变动,类图关系如下

从原本的继承被适配类转变为持有被适配类的实例。涉及到代码修改的只有适配器类:Adapter220To5.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class Adapter220To5  implements IOutput5V {
private Output220V output220;

public Adapter220To5 setOutput220(Output220V output220) {
this.output220 = output220;
return this;
}

@Override
public int output5v() {
int src = output220.output220();

int dts = src / 44;
System.out.println("充电器适配后电压:" + dts);
return dts;
}
}

适配器类在需要持有被适配类的实例,所以在Phone充电方法中传入被适配类的对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class Phone {

public void charging(IOutput5V iOutput5V){
if (iOutput5V.output5v()==5){
System.out.println("电压5v,开始充电");
}else {
System.err.println("电压不符,无法充电");
}
}
public static void main(String[] args) {

new Phone().charging(new Adapter220To5().setOutput220(new Output220V()));
}
}

对象适配器模式说明

  • 对象适配器和类适配器其实算是同一种思想,只不过实现方式不同。
  • 根据合成复用原则,使用组合替代继承,所以它解决了类适配器必须继承被适配类的局限性问题,也不再要求目标接口角色必须是接口。

接口适配器模式

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

接口适配器模式适用于一个接口不想使用其所有的方法的情况

简单的类图结构如下:

代码实现

假定现在的目标接口定义了输出5v、输出20v、输出60v的方法

1
2
3
4
5
6
7
8
public interface IOutput {

int output5();

int output20();

int output60();
}

定义抽象类默认实现目标接口,并持有待适配的对象实例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public abstract class AbsAdapter implements IOutput{
protected Output220V output220;

public AbsAdapter(Output220V output220V) {
this.output220 = output220V;
}

@Override
public int output5() {
return 0;
}

@Override
public int output20() {
return 0;
}

@Override
public int output60() {
return 0;
}
}

当需要使用到输出5v的转换时,或者需要使用输出10v转换时,使用匿名内部类的方式实现内部适配细节

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public class Phone {

public void charging(IOutput iOutput){
if (iOutput.output5()==5){
System.out.println("电压5v,开始充电");
}else {
System.err.println("电压不符,无法充电");
}
}
public static void main(String[] args) {
AbsAdapter absAdapter = new AbsAdapter(new Output220V()) {
@Override
public int output5() {
int src = output220.output220();

int dts = src / 44;
System.out.println("充电器适配后电压:" + dts);
return dts;
}
};
new Phone().charging(absAdapter);
}
}

输出结果:

1
2
3
电源输出电压:220V
充电器适配后电压:5
电压5v,开始充电

适配器模式总结

主要优点:

  • 将目标类和适配者类解耦,通过引入一个适配器类来重用现有的适配者类,无须修改原有结构。
  • 增加了类的透明性和复用性,将具体的业务实现过程封装在适配者类中,对于客户端类而言是透明的,而且提高了适配者的复用性,同一个适配者类可以在多个不同的系统中复用。
  • 灵活性和扩展性都非常好,通过使用配置文件,可以很方便地更换适配器,也可以在不修改原有代码的基础上增加新的适配器类,完全符合“开闭原则”。

适用场景:

  • 系统需要使用一些现有的类,而这些类的接口(如方法名)不符合系统的需要,甚至没有这些类的源代码。
  • 想创建一个可以重复使用的类,用于与一些彼此之间没有太大关联的一些类,包括一些可能在将来引进的类一起工作。

适配器模式在源码中的使用