定义
适配器模式又叫做变压器模式,它的功能是将一个类的接口变成客户端所期望的另一种接口,从而使原本因接口不匹配而导致无法在一起工作的两个类能够一起工作,属于结构型设计模式。
适用场景
提供一个转换器(适配器),将当前系统存在的一个对象转化为客户端能够访问的接口对象。适配器适用于以下几种业务场景:
1、已经存在的类,它的方法和需求不匹配(方法结果相同或相似)的情况。
2、适配器模式不是软件设计阶段考虑的设计模式,是随着软件维护,由于不同产品、不同厂家造成功能类似而接口不相同情况下的解决方案。
生活中也非常的应用场景,例如电源插转换头、手机充电转换头、显示器转接头。
代码实现
适配器模式一般包含三种角色:
目标角色(Target):也就是我们期望的接口;
源角色(Adaptee):存在于系统中,内容满足客户需求(需转换),但接口不匹配的接口实例;
适配器(Adapter):将源角色(Adaptee)转化为目标角色(Target)的类实例;
适配器模式各角色之间的关系如下:
假设当前系统中,客户端需要访问的是Target接口,但Target接口没有一个实例符合需求,而Adaptee 实例符合需求;但是客户端无法直接使用Adaptee(接口不兼容);因此,我们需要一个适配器(Adapter)来进行中转,让Adaptee能转化为Target接口形式。
适配器模式有3种形式:类适配器、对象适配器、接口适配器。
- 类适配器
public interface Target {
int request();
}
public class Adaptee{
public int specificRequest() {
return 220;
}
}
public class Adapter extends Adaptee implements Target {
public int request() {
return super.specificRequest() / 10;
}
}
类适配器的原理就是通过继承来实现适配器功能。具体做法:让Adapter 实现Target接口,并且继承Adaptee,这样Adapter 就具备Target和Adaptee的特性,就可以将两者进行转化。
- 对象适配器
public class Adapter implements Target {
private Adaptee adaptee;
public Adapter(Adaptee adaptee){
this.adaptee = adaptee;
}
public int request() {
return adaptee.specificRequest() / 10;
}
}
对象适配器的原理就是通过组合来实现适配器功能。具体做法:让Adapter 实现Target接口,然后内部持有Adaptee 实例,然后再Target 接口规定的方法内转换Adaptee。
- 接口适配器
public interface Target {
int request1();
int request2();
int request3();
int request4();
}
public abstract class Adapter implements Target {
protected Adaptee adaptee;
public Adapter(Adaptee adaptee){
this.adaptee = adaptee;
}
public int request1() {
return 0;
}
public int request2() {
return 0;
}
public int request3() {
return 0;
}
public int request4() {
return 0;
}
}
接口适配器的关注点与类适配器和对象适配器的关注点不太一样,类适配器和对象适配器着重于将系统存在的一个角色(Adaptee)转化成目标接口(Target)所需内容,而接口适配器的使用场景是解决接口方法过多,如果直接实现接口,那么类会多出许多空实现的方法,类显得很臃肿。此时,使用接口适配器就能让我们只实现我们需要的接口方法,目标更清晰。
在源码中的应用
Spring 中适配器模式也应用得非常广泛,例如:SpringAOP中的AdvisorAdapter类,它有三个实现类MethodBeforeAdviceAdapter、AfterReturningAdviceAdapter 和ThrowsAdviceAdapter;还有SpringMVC中的HandlerAdapter类等
优缺点
优点:
1、能提高类的透明性和复用,现有的类复用但不需要改变
2、目标类和适配器类解耦,提高程序的扩展性
3、在很多业务场景中符合开闭原则
缺点:
1、适配器编写过程需要全面考虑,可能会增加系统的复杂性
2、增加代码阅读难度,降低代码可读性,过多使用适配器会使系统代码变得凌乱