适配器模式是把一个类的接口变成客户端所期待的另一种接口,从而使原本因接口不匹配而无法在一起工作的两个类能够在一起工作。
就像插头转换器,之前入了switch港版,插头是英式的,还好附赠一个插头转换器,适配器就相当于这个转换器。
分为类的适配器与对象的适配器两种
把适配的类的api转化为目标类的api
上图中Adaptee没有2方法,但是客户端却期望调用2方法。为了客户端能够使用Adaptee类,提供中间类Adapter,把Adaptee与Target的api组合起来,Adapter与Adaptee是继承关系,所以这决定了适配器是类适配器。
涉及到的角色:
目标(Target)角色:这就是所期待得到的接口。注意:由于这里讨论的是类适配器,因此目标不能是类。
源(Adapee)角色:现在需要适配的接口。
适配器(Adapter)角色:适配器类是本模式的核心。适配器把源接口转化成目标接口,显然这一角色不可以是接口必须是具体类。
类适配器代码:
public interface Target {
/**
* 这是源类Adaptee也有的方法
*/
public void sampleOperation1();
/**
* 这是源类Adapteee没有的方法
*/
public void sampleOperation2();
}
public class Adaptee {
public void sampleOperation1(){}
}
public class Adapter extends Adaptee implements Target {
/**
* 由于源类Adaptee没有方法sampleOperation2()
* 因此适配器补充上这个方法
*/
@Override
public void sampleOperation2() {
//写相关的代码
}
}
适配器Adapter扩展了源类,也实现了目标接口,且提供了源类没有的接口的实现。
对象适配器模式
对象适配器与类适配器不同的地方在于,对象适配器采用委派的方式将源类与适配器关联到一起(类适配器采用继承)
源代码:
public interface Target {
/**
* 这是源类Adaptee也有的方法
*/
public void sampleOperation1();
/**
* 这是源类Adapteee没有的方法
*/
public void sampleOperation2();
}
public class Adaptee {
public void sampleOperation1(){}
}
public class Adapter {
private Adaptee adaptee;
public Adapter(Adaptee adaptee){
this.adaptee = adaptee;
}
/**
* 源类Adaptee有方法sampleOperation1
* 因此适配器类直接委派即可
*/
public void sampleOperation1(){
this.adaptee.sampleOperation1();
}
/**
* 源类Adaptee没有方法sampleOperation2
* 因此由适配器类需要补充此方法
*/
public void sampleOperation2(){
//写相关的代码
}
}
类适配器与对象适配器的权衡
综上,尽量以对象适配器的实现方式为主,多用聚合,少用继承。当然具体问题具体分析,根据实际需要选择(个人认为实际上就没必要对源类进行重写,如果需要进行重写直接对源类进行修改就行了,除非是没有代码权限,不过如果没有权限的话,那么源类对你来讲更不可见,也就更没有重写的必要了吧。)。
更好的复用性:
系统需要使用现有的类,而此类的接口不符合系统的需要,那么通过适配器模式可以让类获得更好的复用。
更好的扩展性:
在适配器实现功能的时候,也可以调用自己的功能,从而扩展系统的功能。
过多的适配器,会让系统显得更加凌乱,不容易把控。
重构的代价合适的话,确实要比适配器更合适。