在日常工作中可能会遇到现有的类可以满足新需求但略有出入的情况,这时候我们可以选择使用适配器模式把现有的类转换成需要的接口,就像我们的手机或者电脑适配器一样,把220V的交流电转换成手机或者电脑可接收的直流电。
适配器模式
适配器模式(有时候也称包装样式或者包装)将一个类的接口适配成用户所期待的。一个适配允许通常因为接口不兼容而不能在一起工作的类工作在一起,做法是将类自己的接口包裹在一个已存在的类中。
从定义可以看出适配器模式中有三个角色:
- 用户所期待的Target目标类;
- 现有的不能完全满足需求的Adaptee适配者类;
- 把Adaptee适配者类改造成用户所期待的Target目标类的Adapter适配器类。
适配器模式包括类适配器、对象适配器和默认适配器三种,下面逐一介绍。
在介绍之前我们先设定一个功能为输出220V交流电的适配者类:
class AdapteeOutput220VAC{
private Integer voltage;
AdapteeOutput220VAC(){
this.voltage = 220;
}
public void outputVoltage(){
System.out.println("当前电压为:" + voltage + "V");
}
public void setVoltage(Integer voltage){
this.voltage = voltage;
}
public Integer getVoltage(){
return this.voltage;
}
}
功能为输出5V直流电的目标接口:
interface TargetOutput5VDC{
void output5VDC();
}
类适配器
类适配器是通过让我们定义的Adapter适配器类继承Adaptee适配者类且实现Target目标接口实现的。
类图
具体实现
class Adapter extends AdapteeOutput220VAC implements TargetOutput5VDC {
public void output5VDC() {
setVoltage(5);
super.outputVoltage();
}
}
测试程序及输出结果:
测试程序:
public static void main(String[] args) {
TargetOutput5VDC targetOutput5VDC = new Adapter();
targetOutput5VDC.output5VDC();
}
输出结果:
当前电压为:5V
这里有个问题是Target可能不是接口(也可能是抽象类或者具体类),众所周知Java是单继承的,因此那就不能用类适配器了,这个时候可以选择使用对象适配器。
对象适配器
与类适配器不同的是对象适配器不是通过继承而是通过关联(持有适配者引用)来达到适配的目的,因此无论目标接口是接口还是抽象类甚至是具体类都可以让适配器类直接实现或者继承目标接口。并且对象适配器可以把多个适配者都适配到同一目标接口中。
为了验证对象适配器可以适配多个适配者,新的业务场景:各个国家的交流电压可能不太相同,例如美国110V,英国230V,想要实现一个在各个国家都可以使用的手机适配器。
类图
具体实现
适配者类:
//抽象适配者类
abstract class AbstractAdateeOutputAC {
protected Integer voltage;
public void setVoltage(Integer voltage){
this.voltage = voltage;
}
public Integer getVoltage(){
return this.voltage;
}
abstract void outputVoltage();
}
//具体适配者类
class AdapteeOutputChinaVAC extends AbstractAdateeOutputAC{
AdapteeOutputChinaVAC(){
this.voltage = 220;
}
@Override
public void outputVoltage(){
System.out.println("中国交流电压为:" + voltage + "V");
}
}
//具体适配者类
class AdapteeOutputAmericanVAC extends AbstractAdateeOutputAC{
AdapteeOutputAmericanVAC(){
this.voltage = 110;
}
@Override
public void outputVoltage(){
System.out.println("美国交流电压为:" + voltage + "V");
}
}
适配器类:
class Adapter implements TargetOutput5VDC {
private AbstractAdateeOutputAC abstractAdateeOutputAC;
public Adapter(AbstractAdateeOutputAC abstractAdateeOutputAC) {
this.abstractAdateeOutputAC = abstractAdateeOutputAC;
}
public void output5VDC() {
abstractAdateeOutputAC.setVoltage(5);
abstractAdateeOutputAC.outputVoltage();
}
}
测试程序及输出结果:
//测试程序
public static void main(String[] args) {
AbstractAdateeOutputAC acChina = new AdapteeOutputChinaVAC();
Adapter adapter1 = new Adapter(acChina);
adapter1.output5VDC();
AbstractAdateeOutputAC acAmerican = new AdapteeOutputAmericanVAC();
Adapter adapter2 = new Adapter(acAmerican);
adapter2.output5VDC();
}
//输出结果
中国交流电压为:5V
美国交流电压为:5V
默认适配器
在日常工作中可能会遇到需要实现方法比较多的接口,所有该接口的实现类都需要实现该接口的所有方法,这时我们可以使用一个类去实现该接口并提供所有方法的默认实现,之前的实现类继承这个类并重写自己需要的方法就好了。JDK中有许多类似的用法,例如集合框架中的AbstractCollection、AbstractList等,在此不再赘述。