1.引子
早上好!又到了我们一周分享的时候。今天我要分享给你的是适配器设计模式,它是一种常用的结构型设计模式。
说起适配器设计模式,从字面上我们就可以对它有一个直观的认识:适配,通过某种方法手段,把原本不兼容的事情,放到一起彼此谈笑风生,兼容了。即适配器设计模式,是一种解决接口兼容性问题的设计模式。非要举一个例子的话,USB转接头我们都很熟悉,日常生活中通过USB转接头,一边连接电脑,另外一边连接手机,实现电脑与手机之间的数据互传,或者给手机充电,类似下面这样:
上图中,USB数据线即是适配器设计模式中的适配器。
理解了适配器设计模式,主要解决兼容性问题(在编程中主要解决接口兼容性问题)后,接下来我将通过代码案例给你演示,适配器设计模式的实现。你需要留意一下,适配器设计模式在代码层面,有两种实现方式
- 类适配器设计模式:通过继承关系实现
- 对象适配器设计模式:通过组合关系实现
适配器设计模式,代码实现非常简单容易理解。本次借助这篇文章我更期望能够给你带来一些实际项目中,应用适配器设计模式的一些思考。让我们开始吧
2.案例
在编写代码案例前,我们首先理清楚适配器设计模式中有哪些角色,它应该有
- 目标接口Target
- 被适配者Adaptee
- 适配器Adaptor
2.1.继承关系实现适配器
2.1.1.目标接口
/**
* 类适配器设计模式案例:目标接口
*
* @author ThinkPad
* @version 1.0
* @date 2021/3/20 7:57
*/
public interface ITarget {
/**
* 目标方法1
*/
void method1();
/**
*目标方法2
*/
void method2();
/**
*目标方法Target
*/
void methodTarget();
}
2.1.2.被适配者
/**
* 类适配器设计模式案例:被适配者
*
* @author ThinkPad
* @version 1.0
* @date 2021/3/20 7:59
*/
public class Adaptee {
/**
* 被适配方法1
*/
public void method1(){}
/**
* 被适配方法2
*/
public void method2(){}
/**
* 被适配方法Adaptee
*/
public void methodAdaptee(){}
}
2.1.3.适配器
/**
* 类适配器设计模式案例:适配器,通过Adaptor,解决了Adaptee与ITarget之间的兼容性
*
* @author ThinkPad
* @version 1.0
* @date 2021/3/20 8:02
*/
public class Adaptor extends Adaptee implements ITarget{
// 目标方法method1 ,直接复用被适配父类Adaptee中的实现
// 目标方法method2,直接复用被适配父类Adaptee中的实现
/**
* 目标方法Target
*/
@Override
public void methodTarget() {
// 适配父类Adaptee中的方法methodAdaptee
super.methodAdaptee();
}
}
2.2.组合关系实现适配器
2.2.1.目标接口
/**
* 对象适配器设计模式案例:目标接口
*
* @author ThinkPad
* @version 1.0
* @date 2021/3/20 7:57
*/
public interface ITarget {
/**
* 目标方法1
*/
void method1();
/**
*目标方法2
*/
void method2();
/**
*目标方法Target
*/
void methodTarget();
}
2.2.2.被适配者
/**
* 对象适配器设计模式案例:被适配者
*
* @author ThinkPad
* @version 1.0
* @date 2021/3/20 7:59
*/
public class Adaptee {
/**
* 被适配方法1
*/
public void method1(){}
/**
* 被适配方法2
*/
public void method2(){}
/**
* 被适配方法Adaptee
*/
public void methodAdaptee(){}
}
2.2.3.适配器
/**
* 对象适配器设计模式案例:适配器,解决Adaptee与ITarget接口的兼容性
*
* @author ThinkPad
* @version 1.0
* @date 2021/3/20 8:09
*/
public class Adaptor implements ITarget{
// 依赖注入进来
private Adaptee adaptee;
/**
* 目标方法1
*/
@Override
public void method1() {
adaptee.method1();
}
/**
* 目标方法2
*/
@Override
public void method2() {
adaptee.method2();
}
/**
* 目标方法Target
*/
@Override
public void methodTarget() {
adaptee.methodAdaptee();
}
}
2.3.进一步理解适配器设计模式
我们说适配器设计模式,主要是解决接口之间的兼容性问题。而且我们看到无论是通过继承关系实现的类适配器实现代码,还是通过组合关系实现的对象适配器实现代码,都非常简单。
那么这里我有两个小问题,需要你思考一下
- 通常什么场景下,我们需要使用适配器设计模式
- 既然有类适配器实现方式,与对象适配器实现方式,如何在两者之间选择呢
我们一起来分析以上两个问题。在实际应用中,结合适配器设计模式解决兼容性问题的特性,那么如果碰到这样的业务场景,我们适合应用适配器设计模式
- 项目早期接口设计考虑不全面,随着业务的发展,需要改变接口内部实现,或者需要增加新的接口。但是考虑到旧接口(Adaptee)已经在线上使用,不能直接替换,只能通过“补偿”的方式,实现向前兼容。那么这个时候,适合应用适配器设计模式
- 项目依赖了一些第三方外部系统,为了实现与第三方系统解耦,增强扩展性。比如将第三方系统A,无感知的替换为第三方系统B。适合应用适配器设计模式,通过适配器增加中间层,实现项目与第三方系统的解耦
理解了适配器设计模式的合适应用场景,我们再来看如何选择类适配器设计模式实现,还是对象适配器设计模式实现。
其实这个选择并不困难,如果你理解继承,与组合之间的关系,那么在实际项目中,非常容易做出选择,我们一起来看一下
- 如果目标ITarget,与被适配者Adaptee接口相似度比较高,从代码复用性的角度考虑,优先选择类适配器设计模式实现方式
- 如果目标ITarget,与被适配器Adaptee接口相似度不高,从扩展性、灵活性的角度考虑,优先选择对象适配器设计模式实现
基于以上的选择原则,针对我们前面的实现案例,如果是在真实的项目中,你有选择答案了吗?
我们来看ITarget接口拥有方法
- void method1()
- void method2()
- void methodTarget()
我们再来看被适配者Adaptee拥有方法
- void method1()
- void method2()
- void methodAdaptee()
目标接口ITarget与被适配者Adaptee相似度较高,共同拥有method1、method2方法,适合选择类适配器设计模式方式实现。
你看这就是适配器设计模式。最后期望这篇文章能够给你带来关于适配器设计模式的一些不一样的理解