1.什么是适配器模式?
《Head First设计模式》中定义:讲一个类的接口,转换为客户期望的另一个接口,使原本接口不兼容的两个类可以相互合作。
适配器模式有两种形式:类适配器、对象适配器。类适配器需要用到“多重继承”;对象适配器使用组合。对象适配器不仅可以适配某个类,也可以适配该类的任何子类(因为采用组合的方式,实现了共同接口的类都可以适配),但是必须实现被适配者类的所有方法。类适配器只能适配某个特定的被适配者类(因为采用继承的方式,相当于被适配者的专用适配器),优点是不用重新实现整个被适配者,还可以覆盖被适配者的方法。
2. 角色
客户端(Client):负责创建调用者对象,并确定他们之间的调用关系
目标对象(Target):目标对象接口。一般是一个抽象接口。
适配器(Adapter):将被适配者接口转换为目标对象接口。是一个具体的类。
被适配者(Adaptee):想要被转换的对象接口,自己拥有一套处理机制。
注意:原来使用的是目标接口中的方法,适配后使用的是被适配者中的方法
图片来源于《Head First设计模式》
3. 优点
(1)更好的复用性:系统需要使用现有的类,但是类的接口不符合系统需要,可以通过适配器来更好的复用这些类。
(2)更好的扩展性:实现适配器的时候可以调用自己的功能来扩展系统功能。
(3)更好的开闭原则:使用适配器只需要维护适配器类代码,不需要更改目标接口和被适配接口的代码,符合开闭原则。
4.缺点
(1)适配器模式使用过多会使系统非常零乱,不易于整体把握。有时候调用的是A接口,但实际上被转变成了B接口。
5. 使用场景
(1)系统内双方接口不一致且不能修改时,如果想要一起合作可以考虑使用适配器模式。
(2)系统与系统之间的接口调用,如果接口与接口不一致可以考虑使用适配器模式。
(3)系统内使用多个组件,组件功能类似,接口不统一,而且经常容易更换时,可以考虑使用适配器模式。
(4)个人理解,系统内部有需要使用适配器的情况下,如果目标类和被适配类不是不能更改的那种,最好首先考虑重构代码。
6.示例代码
6.1 类适配器示例代码
/**
* 目标类接口
*/
public interface Target {
public void request();
}
/**
* 具体的目标类
*/
public class ConcreteTarget implements Target {
@Override
public void request() {
System.out.println("ConcreteTarget");
}
}
/**
* 被适配者类
*/
public class Adaptee {
public void doSomething(){
System.out.println("Adaptee");
}
}
/**
* 适配器类
*/
public class Adapter extends Adaptee implements Target{
@Override
public void request() {
super.doSomething();
}
}
/**
* 客户端
*/
public class Client {
public static void main(String[] args) {
/*适配之前的操作*/
Target before=new ConcreteTarget();
before.request();
//适配之后的操作
Target now = new Adapter();
now.request();
}
}
/**
* 测试结果
*/
ConcreteTarget
Adaptee
6.2
对象适配器示例代码
/**
* 目标类接口
*/
public interface Target {
public void request();
}
/**
* 具体的目标类
*/
public class ConcreteTarget implements Target {
@Override
public void request() {
System.out.println("ConcreteTarget");
}
}
/**
* 被适配者类
*/
public class Adaptee {
public void doSomething(){
System.out.println("Adaptee");
}
}
/**
* 被适配者的子类
*/
public class AdapteeSon extends Adaptee {
@Override
public void doSomething() {
System.out.println("AdapteeSon........");
}
}
/**
* 适配器类
*/
public class Adapter implements Target {
//有一个被适配者的引用
Adaptee adaptee;
public Adapter() {}
public Adapter(Adaptee adaptee) {
this.adaptee=adaptee;
}
@Override
public void request() {
adaptee.doSomething();
}
}
/**
* 客户端
*/
public class Client {
public static void main(String[] args) {
//适配之前的操作
Target before=new ConcreteTarget();
before.request();
//适配之后的操作
Adaptee father=new Adaptee();
Target now = new Adapter(father);
now.request();
//用被适配者的子类来适配目标接口
Adaptee son=new AdapteeSon();
Target nowSon=new Adapter(son);
nowSon.request();
}
}
/**
* 测试结果
*/
ConcreteTarget
Adaptee
AdapteeSon........
6.3 适配器实例代码
出国旅游常常会因为外国电压标准和国内电压标准不同而导致不能给手机充电的情况,一般出国的人都会带一个电压适配器,将外国的110v电压转换为国内220v电压,这样就可以给手机充电了。
/**
* 国外110v电流标准接口(Target)
*/
public interface Electric110V {
/**
* 提供接通电源的方法
*/
public void turnOnElectricity();
}
/**
* 使用110v电流标准的插座(ConcreteTarget)
*/
public class Socket110v implements Electric110V {
/**
*接通电源
*/
@Override
public void turnOnElectricity() {
System.out.println("you can use the 110v Electricity");
}
}
/**
* 国内220v电流标准接口(抽象adaptee)
*/
public interface Electric220V {
public void turnOnElectricity();
}
/**
* 使用220v电流标准的插座对象(具体adaptee)
*/
public class Socket220v implements Electric220V{
/**
*接通电源
*/
@Override
public void turnOnElectricity() {
System.out.println("you can use 220v Electricity");
}
}
/**
* 插座适配器(adapter)
*/
public class SocketAdapter implements Electric110V{
Electric220V electric220V;
public SocketAdapter() {
}
public SocketAdapter(Electric220V electric220V) {
this.electric220V=electric220V;
}
/**
* 将110v的电流转换为220v
*/
@Override
public void turnOnElectricity() {
System.out.println("110v turn to 220v");
electric220V.turnOnElectricity();
}
}
/**
* 宾馆对象(Client)
*/
public class Hotel {
//使用110v电流
Electric110V electric110V;
public Hotel(){}
public Hotel(Electric110V electric110V) {
this.electric110V=electric110V;
}
public void setElectric(Electric110V electric110V){
this.electric110V=electric110V;
}
/**
* 宾馆接通电源
*/
public void provideElectric(){
electric110V.turnOnElectricity();
}
public static void main(String[] args) {
//住进一个提供110v电流插座的宾馆
Hotel hotel=new Hotel();
Socket110v socket110v=new Socket110v();
hotel.setElectric(socket110v);
//插卡通电
hotel.provideElectric();
//拿出国内插座(为什么要用插座,是为了多几个插口,哈哈哈,有的电压适配器直接可以提供充电,这就需要我们自己实现该方法,我这个适配器只支持插上220v的插座)
Socket220v socket220v=new Socket220v();
//将国内插座插在电压适配器上
SocketAdapter a=new SocketAdapter(socket220v);
hotel.setElectric(a);
//插卡通电
hotel.provideElectric();
}
}
/**
* 测试结果
*/
you can use the 110v Electricity
110v turn to 220v
you can use 220v Electricity
【四川乐山程序员联盟,欢迎大家加群相互交流学习5 7 1 8 1 4 7 4 3】