设计模式——适配器模式
基本介绍
- 适配器模式(Adapter Pattern)将某个类的接口转换成客户端期望的另一个接口表示,主的目的是兼容性,让原本因接口不匹配不能一起工作的两个类可以协同工作。其别名为包装器(Wrapper);
- 适配器模式属于结构型模式;
- 主要分为三类:类适配器模式、对象适配器模式、接口适配器模式;
问题引入
以生活中充电器的例子来讲解适配器,充电器本身相当于Adapter
,220V 交流电相当于src (即被适配者)
,我们的适配完成的目标dst是 5V 直流电
;
类适配器模式
Adapter类
通过继承src类
,实现dst类接口
,完成 src->dst 的适配。
UML
代码创建
被适配器的类Voltage220V
的创建
package edu.hebeu.classadapter;
public class Voltage220V { // 这个类相当于被适配的类target
public int outputVeltage220() {
System.out.println("提供了220V的交流~电");
return 220;
}
}
被适配之后的目标接口Voltage5V
的创建,该接口需要定制和被适配器类的同名方法,用来在适配器类中覆盖原方法,完成适配
package edu.hebeu.classadapter;
public interface Voltage5V { // 这个类相当于被适配器适配之后的目标接口
int outputVeltage5();
}
适配器类VoltageAdapter
的创建,该类继承被适配器类Voltage220V
,实现被适配之后的目标接口Voltager5V
完成适配,如下代码:
package edu.hebeu.classadapter;
public class VoltageAdapter extends Voltage220V implements Voltage5V { // 这个类相当于适配器
@Override
public int outputVeltage5() {
int sourceVoltage = outputVeltage220();
int targetVoltage = sourceVoltage / 44;
System.out.println("输出了" + targetVoltage + "V-直流电");
return targetVoltage;
}
}
使用适配器的类Phone
的创建,该类直接调用适配之后的目标接口内的方法,该方法就会调用其子类的实现方法,实现正常的调用
package edu.hebeu.classadapter;
public class Phone {
public void charging(Voltage5V voltage5v) {
int voltage = voltage5v.outputVeltage5();
if(voltage != 5) {
System.out.println("我要炸开了!!!!!");
return;
}
System.out.println("正在充电...");
}
}
测试类Client
的创建
package edu.hebeu.classadapter;
/**
* 这个例子使用类适配器
* @author 13651
*
*/
public class Client {
public static void main(String[] args) {
System.out.println("---------类适配器----------");
Phone phone = new Phone();
phone.charging(new VoltageAdapter());
}
}
测试
细节和注意事项
- Java 是单继承机制,所以类适配器需要继承
src 类
这一点算是一个缺点, 因为这要求dst 必须是接口
,有一定局限性; src 类
的方法在Adapter
中都会暴露出来,也增加了使用的成本。- 由于其继承了 src 类,所以它可以根据需求重写 src 类的方法,使得 Adapter 的灵活性增强了。
对象适配器模式
基本介绍
- 基本思路和类的适配器模式相同,只是将 Adapter 类作修改,不是继承 src 类,而是持有 src 类的实例,以解决兼容性的问题。 即:持有 src 类,实现 dst 类接口,完成 src->dst 的适配;
- 根据“合成复用原则”,在系统中尽量使用关联关系(聚合)来替代继承关系;
- 对象适配器模式是适配器模式常用的一种;
UML
代码创建
被适配器类Voltage220V
的创建
package edu.hebeu.objectadapter;
public class Voltage220V { // 这个类相当于被适配的类target
public int outputVeltage220() {
System.out.println("提供了220V的交流~电");
return 220;
}
}
适配的目标接口类Voltage5V
创建
package edu.hebeu.objectadapter;
public interface Voltage5V { // 这个类相当于被适配器适配之后的目标接口
int outputVeltage5();
}
适配器类VoltageAdapter
的创建
package edu.hebeu.objectadapter;
public class VoltageAdapter implements Voltage5V { // 这个类相当于适配器
private Voltage220V voltage220v;
public VoltageAdapter(Voltage220V voltage220v) {
this.voltage220v = voltage220v;
}
@Override
public int outputVeltage5() {
int sourceVoltage = voltage220v.outputVeltage220();
int targetVoltage = sourceVoltage / 44;
System.out.println("输出了" + targetVoltage + "V-直流电");
return targetVoltage;
}
}
使用类Phone
的创建
package edu.hebeu.objectadapter;
public class Phone {
public void charging(Voltage5V voltage5v) {
int voltage = voltage5v.outputVeltage5();
if(voltage != 5) {
System.out.println("我要炸开了!!!!!");
return;
}
System.out.println("正在充电...");
}
}
测试类Client
的创建
package edu.hebeu.objectadapter;
/**
* 这个例子使用对象适配器
* @author 13651
*
*/
public class Client {
public static void main(String[] args) {
System.out.println("-------对象适配器-------");
Phone phone = new Phone();
phone.charging(new VoltageAdapter(new Voltage220V()));
}
}
细节和注意事项
- 对象适配器和类适配器其实算是同一种思想,只不过实现方式不同。根据合成复用原则,使用组合替代继承, 所以它解决了类适配器必须继承 src 的局限性问题,也不再要求 dst必须是接口;
- 使用成本更低,更灵活;
接口适配器模式
基本介绍
- 一些书籍称为:适配器模式(Default Adapter Pattern)或缺省适配器模式;
- 核心思路:当不需要全部实现接口提供的方法时,可先设计一个抽象类实现接口,并为该接口中每个方法提供一个默认实现(空方法),那么该抽象类的子类可有选择地覆盖父类的某些方法来实现需求;
- 适用于一个接口不想使用其所有的方法的情况;
UML
代码创建
创建接口类IUtils
package edu.hebeu.interfaceadapter;
public interface IUtils {
void m1();
void m2();
void m3();
// ...
}
创建一个抽象类AbsUtils
来默认实现上述的接口
package edu.hebeu.interfaceadapter;
/**
* 这个抽象类实现IUtils接口,并将接口内的方法都 默认实现(空实现),如下所示
* @author 13651
*
*/
public abstract class AbsUtils implements IUtils{
@Override
public void m1() {
}
@Override
public void m2() {
}
@Override
public void m3() {
}
// ...
}
此时客户端Client
可以通过上述的抽象类AbsUtils
来实现我们需要使用的方法,这就是接口适配器模式的大体思路,如下:
package edu.hebeu.interfaceadapter;
public class Client {
public static void main(String[] args) {
// 此时将需要使用的具体方法进行具体实现
AbsUtils absUtils = new AbsUtils() {
@Override
public void m2() {
System.out.println("具体的实现m2()方法...");
}
};
absUtils.m2();
}
}