1. 介绍
适配器模式是把一个类的接口变换成客户端的所期待的另一个接口,从而使原本因接口不匹配而无法在一起工作的两个类能够在一起工作。
2. 分类
适配器模式有类的适配器模式和对象的适配器模式两种形式。
2.1 类的适配器模式
类的适配器模式是把适配的类的API转换成为目标类的API.
从上图中可以看出:Target期待调用Request方法,而Adaptee并没有(这就是所谓的不兼容了)。
为使Target能够使用Adaptee类里的SpecificRequest方法,故提供一个中间环节Adapter类(继承Adaptee & 实现Target接口),把Adaptee的API与Target的API衔接起来(适配)。
模式所涉及的角色有:
- 目标角色(Target):这就是所期待得到的接口
- 源角色(Adapee):现在需要适配的接口
- 适配器角色(Adaper):适配器类,把源接口转换成目标接口
具体实现
(1)Target接口
public interface Target{
//这是源类Adaptee没有的接口
public void Request();
}
(2)源类(Adaptee)
public class Adaptee {
public void SpecificRequest() {}
}
(3)适配器类(Adapter)
//继承Adaptee并实现Target
public class Adapter extends Adaptee implements Target {
//在适配器中将SpecificRequest()方法转化为Request()
@Override
public void Request() {
this.SpecificRequest();
}
}
(4)定义具体使用类,并通过Adapter类调用所需要的方法
public class AdapterPattern {
public static void main(String[] args) {
Target mAdapter = new Adapter();
mAdapter.Request();
}
}
2.2 对象的适配器模式
与类的适配器模式相同,对象的适配器模式也是把适配的类的API转换成为目标类的API;与类的适配器模式不同的是,对象的适配器模式不是使用继承关系连接到Adaptee类,而是使用委派关系连接到Adaptee类。
从上图可以看出:Target期待调用Request方法,而Adaptee并没有,因此提供一个包装类Adapter,这个包装类包装了一个Adaptee的实例,从而能够把Adaptee的API与Target类的API衔接起来。Adapter与Adaptee是委派关系,这决定了适配器模式是对象适配器模式。
具体实现
(1)Target接口
public interface Target{
//这是源类Adaptee没有的接口
public void Request();
}
(2)源类(Adaptee)
public class Adaptee {
public void SpecificRequest() {}
}
(3)适配器类(Adapter)
//不在继承Adaptee类
public class Adapter implements Target {
//直接关联被适配类
private Adaptee adaptee;
//可以通过构造函数传入具体需要适配的被适配类对象
public Adapter(Adaptee adaptee) {
this.adaptee = adaptee;
}
@Override
public void Request() {
//这里使用委托方式完成转换
this.adaptee.SpecificRequest();
}
}
(4)定义具体使用类,并通过Adapter类调用所需要的方法
public class AdapterPattern {
public static void main(String[] args) {
//需要先创建一个被适配类的对象作为参数
Target mAdapter = new Adapter(new Adaptee());
mAdapter.Request();
}
}
3. 适配器模式的优缺点
优点
- 更好的复用性, 可以更好地复用现有的类
- 更好的扩展性, 在实现适配器功能时,可以调用自己开发的功能,从而自然地扩展系统功能。
- 解耦性,将目标类和适配者类解耦
缺点
过多使用使用适配器,会让系统非常零乱,不易整体把握。
4. 对比类的适配器模式和对象的适配器模式
类的适配器模式:
- 使用对象继承方式,是静态定义方式,由于直接继承了Adaptee类,使得不能再和Adaptee的子类一起工作了;
- 类适配器可以重新定义Adaptee的部分行为,相当于子类覆盖父类的部分实现;
- 仅仅引入了一个对象,并不需要额外的引用来间接得到adapter。
对象适配器模式:
- 使用对象组合的方式,是动态组合的方式,因此一个适配器可以把多种不同的源适配到同一目标,换言之,同一个适配器可以把源类和它的子类都是配到目标接口,因为对象适配器采用的是对象组合关系,只要对象类型正确,是不是子类都无所谓。
- 对象适配器要重新定义Adaptee的行为比较困难,这种情况下,需要定义Adaptee的子类来实现重新定义,然后让适配器组合子类。虽然重新定义Adaptee的行为比较困难,但是想要增加一些新的行为则很方便,而且新增加的的行为可同时适用于所有源。
- 对象适配器需要额外的引用来间接得到Adapter。
建议尽量使用对象适配器的实现方式,对用组合,少用继承。当然,具体问题具体分析,根据需要来选用实现方式,最合适的才是最好的。