适配器设计模式有两种功能:
- 作为两个不兼容的接口之间的桥梁,使接口不匹配的两个类能够在一起工作
- 简单适配器功能
1. 功能一:兼容不兼容接口
现有如下设备:
- 苹果手机(Target)
- 苹果充电线
- 安卓充电线
- 适配器(上面有苹果充电头和安卓的插口)
1.1. 类适配器
与对象适配器相同的是:把适配的类的API转换成为目标类的API。
与对象适配器不同的是:
类适配器使用继承关系连接到Adaptee(被适配类);
对象适配器使用委派关系连接到Adaptee类。
定义 Target接口代表苹果手机的接口(目标类);
定义 AppleDataLine类实现Target接口,表示苹果手机充电线可以连接苹果手机;
定义 AndroidDataLine类,表示安卓手机充电线,连接不了苹果手机(被适配类);
定义 Adapter类继承AndroidDataLine,实现Target接口,表示适配器一端连接安卓充电线,一端连接苹果手机;
Adapter和AndroidDataLine是继承关系,这决定了该适配器类型为类适配器
// Target 目标接口
interface Target {
void iphoneConnect();
}
//苹果数据线
class AppleDataLine implements Target{
@Override
public void iphoneConnect() {
System.out.println("用苹果线接苹果手机");
}
}
//安卓数据线
class AndroidDataLine {
public void androidConnect(){
System.out.println("连接了安卓线");
}
}
//适配器
class Adapter extends AndroidDataLine implements Target{
@Override
public void iphoneConnect() {
System.out.print("向苹果手机");
super.androidConnect();
}
}
//测试主类
public class TestAdapterModule {
public static void main(String[] args) {
Target target = new AppleDataLine();
target.iphoneConnect();
Target adapter = new Adapter();
adapter.iphoneConnect();
}
}
1.2. 对象适配器
与类适配器相同的是:把适配的类的API转换成为目标类的API。
与类适配器不同的是:
对象适配器使用委派关系连接到Adaptee类;
类适配器使用继承关系连接到Adaptee(被适配类)。
定义 Target接口代表苹果手机的接口(目标类);
定义 AppleDataLine类实现Target接口,表示苹果手机充电线可以连接苹果手机;
定义 AndroidDataLine类,表示安卓手机充电线,连接不了苹果手机(被适配类);
定义 Adapter类实现Target接口。通过有参构造传入AndroidDataLine对象,在重写的接口方法中调用AndroidDataLine对象的相应方法。
// Target 目标接口
interface Target {
void connect();
}
//苹果数据线
class AppleDataLine implements Target{
@Override
public void connect() {
System.out.println("用苹果线接苹果手机");
}
}
//安卓数据线
class AndroidDataLine {
public void androidConnect(){
System.out.println("连接了安卓线");
}
}
//适配器
class Adapter implements Target {
//被适配对象
private AndroidDataLine androidDataLine;
public Adapter(AndroidDataLine androidDataLine){
this.androidDataLine = androidDataLine;
}
@Override
public void connect() {
//调用被适配对象的方法
androidDataLine.androidConnect();
}
}
//测试主类
public class TestAdapterModule {
public static void main(String[] args) {
Target target = new AppleDataLine();
target.connect();
Target adapter = new Adapter(new AndroidDataLine());
adapter.connect();
}
}
2. 功能二:简单适配
类C想重写接口A中的部分方法,但实现A接口就必须重写所有的方法;
所以定义抽象类B实现A接口;
C继承B,可以重写需要的部分方法。
3. 适配器模式的优缺点
3.1. 总体优缺点
优点:
1.更好的复用性
系统需要使用现有的类,而此类的接口不符合系统的需要。那么通过适配器模式就可以让这些功能得到更好的复用。
2.透明、简单
客户端可以调用同一接口,因而对客户端来说是透明的。这样做更简单,更直接。
3.更好的扩展性
在实现适配器功能的时候,可以调用自己开发的功能,从而自然地扩展系统的功能。
4.解耦性
将目标类和适配者类解耦,通过引入一个适配器类重用现有的适配者类,而无需修改原有代码。
5.符合开放-关闭原则
同一个适配器可以把适配者类和它的子类都适配到目标接口;可以为不同的目标接口实现不同的适配器,而不需要修改待适配类。
缺点:
过多的使用适配器,会让系统非常零乱,不易整体进行把握。
3.2. 类的适配器模式优缺点
优点:仅仅引入一个对象(Adapter),不需要额外字段引用Adaptee实例。
缺点:使用对象继承的方式,是静态的定义方式。
3.3. 对象的适配器模式优缺点
优点:采用“对象组合”的方式,是动态组合。
缺点:需要引入对象实例。
4. 应用场景
4.1. 适配器的使用场景
- 系统需要复用现有类,而该类的接口不符合系统的需求,可以使用适配器模式让接口不兼容的类一起工作;
- 多个组件功能类似,但接口不统一会经常切换,用适配器模式,使客户端可以用统一的接口使用它们。
4.2. 类和对象适配器模式的使用场景
结合各自的优点:
对象的适配器模式是对象的动态组合,更灵活,当需要适配Adaptee和Adaptee的子类时,可以使用对象的适配器模式。
类的适配器模式更加方便,并且因为继承了Adaptee的缘故,可以重定义Adaptee的部分实现方法。
4.3. JDK中的应用实例
java.util.concurrent.Callable传入Thread的过程:
1.自定义的MyThread类实现了Callable接口,作为Adaptee(被适配类);
2.Thread类的有参构造需要传入Runnable接口的实现类;
3.Runnable接口作为Target(目标类);
4.FutureTask作为Runnable接口的实现类,作为Adapter(适配器);
5.FutureTask传入Callable的实现类,通过对象的适配器模式委派MyThread对象的call()方法;
6.将FutureTask类对象传入Thread的构造方法,构成完整的适配器模式。```java public class JDKInstance { public static void main(String[] args) {
} }MyThread myThread = new MyThread();
FutureTask<String> futureTask = new FutureTask<>(myThread);
new Thread(futureTask).start();
class MyThread implements Callable