适配器模式(Adapter Pattern):
将一个类的接口转换成客户希望的另一个接口。Adapter模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。(Convert the interface of a class into another interface clients except. Adapter lets classes work together that couldn’t otherwise because of incompatible interfaces.)
定义一个包装类,用于包装不兼容接口的对象:
- 包装类 = 适配器Adapter;
- 被包装对象 = 适配者Adaptee = 被适配的类
使用场景:
- 系统需要复用现有类,而该类的接口不符合系统的需求,可以使用适配器模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。
- 多个组件功能类似,但接口不统一且可能会经常切换时,可使用适配器模式,使得客户端可以以统一的接口使用它们
- 需要一个统一的输出接口,但是输入类型却不可预知。
主要作用:把一个类的接口变换成客户端所期待的另一种接口,从而使原本接口不匹配而无法一起工作的两个类能够在一起工作。
类的适配器模式和对象的适配器模式的选择:
适配器模式的形式分为:类的适配器模式 & 对象的适配器模式
- 灵活使用时:选择对象的适配器模式,类适配器使用对象继承的方式,是静态的定义方式;而对象适配器使用对象组合的方式,是动态组合的方式。
- 需要同时配源类和其子类:选择对象的适配器,对于对象适配器,一个适配器可以把多种不同的源适配到同一个目标。
- 需要重新定义Adaptee的部分行为:选择类适配器。对于类适配器,适配器可以重定义Adaptee的部分行为,相当于子类覆盖父类的部分实现方法。对于对象适配器,要重定义Adaptee的行为比较困难。
- 仅仅希望使用方便时:选择类适配器,对于类适配器,仅仅引入了一个对象,并不需要额外的引用来间接得到Adaptee。对于对象适配器,需要额外的引用来间接得到Adaptee。
下面以一个案例来介绍设配器模式:该过程大概分成4步:
步骤1:定义目标接口(Target):客户所期待的接口。目标可以是具体的或抽象
的类,也可以是接口。
public interface Target {
void handleReq();
}
步骤2:定义 需要适配的类(Adaptee):需要适配的类或适配者类。
/**
* 被适配的类
* (相当于例子中的,PS/2键盘)
*/
public class Adaptee {
public void request(){
System.out.println("可以完成客户请求的需要的功能!");
}
}
步骤3:定义适配器(Adapter):通过包装一个需要适配的对象,把原接口转换成
目标接口。
类适配器方式:
/**
* 适配器 (类适配器方式)
* (相当于usb和ps/2的转接器)
*/
public class Adapter extends Adaptee implements Target {
@Override
public void handleReq() {
super.request();
}
}
对象适配器方式:
/**
* 适配器 (对象适配器方式,使用了组合的方式跟被适配对象整合)
* (相当于usb和ps/2的转接器)
*/
public class Adapter2 implements Target {
private Adaptee adaptee;
@Override
public void handleReq() {
adaptee.request();
}
public Adapter2(Adaptee adaptee) {
super();
this.adaptee = adaptee;
}
}
步骤4:测试
/**
* 客户端类:测试
*/
public class Client {
public void test1(Target t){
t.handleReq();
}
public static void main(String[] args) {
Client c = new Client();
Adaptee a = new Adaptee();
// Target t = new Adapter();
Target t = new Adapter2(a);
c.test1(t);
}
}
测试结果如下图所示:
如果想了解更多设计模式,可点击:设计模式概述 以及 23种设计模式的介绍