适配器模式
认识
适配器模式是将一个类的接口变为客户端想要的另外一个接口,从而使原本因接口不匹配无法在一起工作的两个类能够在一起工作。适配器的目的是复用已有的功能。
适配器分为类适配器和对象适配器两种
缺省适配:为一个接口提供缺省实现,一般是一个抽象类
适配器模式跟代理模式的不同之处:适配器模式中适配器和被适配对象中的接口方法不一致,适配器对被适配对象中的接口进行了改造或者扩展。代理模式中代理对象和被代理对象实现同一个接口,可以相互替换,代理对象只是对被代理对象中接口方法中的逻辑进行了改变,如添加权限控制。
思考
适配器模式可以对一个接口的所有子类进行适配,对象适配器中持有一个父类指针。不需要单独去对每个子类建立适配器。
适配器模式实质:转换接口,复用功能,通过适配器将老的接口实现类中的方法转换为新的接口中的方法
优先使用对象适配器,多用合成/聚合,少用继承。
使用场景
如果定义了新的接口跟已存在一个实现类不兼容,但是又在新的接口中又想使用实现类中方法,这时使用适配器模式实现复用实现类中的功能。
优缺点
优点
- 更好的复用性:能够兼容使用老的接口
- 开闭原则:避免了对老接口的修改,通过添加适配器实现兼容,达到更好的扩展性
缺点
- 过多的使用适配器模式,会导致调用零乱,明明调用A接口,在A接口中实际调用的是B接口,脱离控制。如果不是很有必要,可以不使用适配器,而是对系统进行重构。
UML图
类适配器:
采用继承方式,即适配器继承被适配类
- 目标接口(Target):客户端真正想要的接口
- 被适配接口(Adaptee):已有的接口实现类,与客户端最新需要的接口不兼容
- 适配器(Adapter):适配器,实现Target和继承Adaptee,客户端调动Adapter,既可以调用Target中的接口方法,也可以调用Adapter继承Adaptee中老的方法
对象适配器:
使用对象动态组合方式,即适配器持有一个被适配对象
- 目标接口(Target):客户端真正想要的接口
- 被适配接口(Adaptee):已有的接口实现类,与客户端最新需要的接口不兼容
- 适配器(Adapter):适配器,实现Target,持有一个Adaptee对象,对于新的接口,调用Adapter中实现的方法,对于老的方法,使用Adaptee对象进行调用
缺省适配
很多情况下,接口中定义了特别多方法,而一个类去实现一个接口,必须要实现所有的方法,但是有些类只是使用到了接口中很少的方法,对于不使用的方法就只能空着,这样会对客户端的调用造成困扰。这时就需要使用一个抽象类去实现接口,在抽象类中给出所有方法的”平庸”实现。从这个抽象类再继承下去的子类就不必实现所有的方法了。,在java源码中很多地方都使用到了这种处理,如List中等。缺省适配的用意是为了避免子类去处理自己不关注的接口方法
代码实现
类适配器:
适配器继承被适配对象,实现目标接口,客户端使用适配器进行调用,对于目标接口中新的方法,适配器进行实现,对于老的接口方法,调用适配器继承而来的被适配类中的方法,从而实现接口兼容。
/**
* 客户端需要的接口
*/
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() {
//写相关的代码
}
}
对象适配器:
适配器实现目标对象,通过构造方法持有一个被适配对象,客户端使用适配器进行调用,对于新的接口调用适配器中的方法,对于老的接口实现,适配器使用被适配对象调用被适配对象中的方法,从而实现接口兼容。
/**
* 客户端需要的接口
*/
public interface Target {
public void request1();
public void request2();
}
/**
* 已经存在的接口,这个接口需要被适配
*/
public class Adaptee {
/**
* 示意方法,原本已经存在,已经实现的方法
*/
public void request1() {
//具体的功能处理
}
}
/**
* 适配器
*/
public class Adapter implements Target {
/**
* 持有需要被适配的接口对象
*/
private Adaptee adaptee;
/**
* 构造方法,传入需要被适配的对象
* @param adaptee 需要被适配的对象
*/
public Adapter(Adaptee adaptee) {
this.adaptee = adaptee;
}
public void request1() {
//可能转调已经实现了的方法,进行适配
adaptee.request1();
}
public void request2() {
//业务代码
}
}
/**
* 使用适配器的客户端
*/
public class Client {
public static void main(String[] args) {
//创建需被适配的对象
Adaptee adaptee = new Adaptee();
//创建客户端需要调用的接口对象
Target target = new Adapter(adaptee);
//请求处理
target.request();
}
}
缺省适配:
使用抽象类实现接口,对接口中方法进行默认实现。