适配器模式
一、概念
- 将一个类的接口转换成客户希望的另外一个接口,使得原本由于接口不兼容而不能在一起工作的 那些类能一起工作。
适配的意识是适应,匹配。通俗的讲,适配器模式适用于有关性但不兼容的结构,源接口通过一个中间件转换后才可以适用于目标接口,这个转换过程就是适配,这个中间件就称之为适配器。
比如家用电源输出电压,USB数据线输入电压。但这俩个接口无法兼容,因为一个输出220V,一个输入5V,通过适配器将输入220V转换成输出5V之后才能一个工作。
二、UML图
摘自知乎:https://zhuanlan.zhihu.com/p/369272002
从上图可见,适配器模式有三个角色
- Target:是一个接口,它是我们客户端使用的目标借口。
- Adaptee:我们想要使用的接口与Target不兼容的类,它可以是一个接口,也可以是一个类。
- Adapter:适配器类,此模式的核心。他需要实现目标接口Target而且必须要引用Adaptee,因为我们要在此类中包装Adaptee的功能。
三、实例
我们列举一个手机充电需要5V电压,而电源提供的是220V的电压,使用适配器解决来解决的栗子。
- Target
/**
* <p>5V的电源</P>
*
* @author hanchao
*/
public interface V5Power {
/**
* 获取名称
*/
String getName();
/**
* 获取电压
*/
Integer getVoltage();
}
然后定义一个充电宝实现该接口:
/**
* <p>充电宝</P>
*
* @author hanchao
*/
public class PortableBatteryPower implements V5Power {
@Override
public String getName() {
return "充电宝";
}
@Override
public Integer getVoltage() {
return 5;
}
}
然后,定义一个手机Phone,它具有充电功能batteryCharge(),其能接受的参数是V5Power类型的。
/**
* <p>手机</P>
*
* @author hanchao
*/
@Slf4j
public class Phone {
/**
* 充电
*/
public void batteryCharge(V5Power v5Power) {
log.info("1.连接电源 ==> " + v5Power.getName());
log.info("2.当前电压 : " + v5Power.getVoltage());
log.info("3.进行充电 ... ");
}
}
- Adaptee
/**
* <p>220V的电源</P>
*
* @author hanchao
*/
public interface V220Power {
/**
* 获取名称
*/
String getName();
/**
* 获取电压
*/
Integer getVoltage();
}
220V电源:实现:家用电源:HouseholdPower
/**
* <p>家用电源</P>
*
* @author hanchao
*/
public class HouseholdPower implements V220Power {
@Override
public String getName() {
return "家用电源";
}
@Override
public Integer getVoltage() {
return 220;
}
}
因为手机Phone的充电方法batteryCharge(V5Power v5Power)参数是V5Power类型的,肯定无法直接传入V220Power类型的参数。
- Adapter
此时,我们需要实现一个适配器Adapter,这个适配器应该实现以下两个功能: - 它的类型应是V5Power的,如此才能作为batteryCharge()方法的参数。所以有:Adapter implements V5Power。
- 它应包含V220Power的对象,如此才能实现最初的目的:使用V220的电源。所以有成员变量:V220Power v220Power。
/**
* <p>USB接口转换器</P>
* <p>
* 1.实现适配目标对象V5Power
*
* @author hanchao
*/
@Slf4j
public class V220ToV5Adapter implements V5Power {
/**
* 2.以组合的方式持有被适配对象v220Power
*/
private V220Power v220Power;
/**
* 3.在构造时初始化被适配对象v220Power
*/
public V220ToV5Adapter(V220Power v220Power) {
this.v220Power = v220Power;
}
/**
* 重写V5Power的方法,完成V220到V5的转换过程
*/
@Override
public String getName() {
return " 电源适配器 ==> " + v220Power.getName();
}
/**
* 重写V5Power的方法,完成V220到V5的转换过程
*/
@Override
public Integer getVoltage() {
log.info("原始电压为:" + v220Power.getVoltage());
log.info("进行电压转换:" + v220Power.getVoltage() + " --> " + 5);
log.info("转换之后的电源为:5");
return 5;
}
}
测试代码:AdapterDemo
public static void main(String[] args) {
//首先,需要一部手机
Phone phone = new Phone();
log.info("如果只有家用电源,则需要通过电源适配器进行转换");
V220Power v220Power = new HouseholdPower();
v5Power = new V220ToV5Adapter(v220Power);
phone.batteryCharge(v5Power);
}
测试结果:
2019-07-09 13:01:44,981 INFO [main-1] pers.hanchao.designpattern.adapter.AdapterDemo:26 - 如果只有家用电源,则需要通过电源适配器进行转换
2019-07-09 13:01:44,985 INFO [main-1] pers.hanchao.designpattern.adapter.Phone:18 - 1.连接电源 ==> 电源适配器 ==> 家用电源
2019-07-09 13:01:44,985 INFO [main-1] pers.hanchao.designpattern.adapter.adapter.V220ToV5Adapter:41 - 原始电压为:220
2019-07-09 13:01:44,986 INFO [main-1] pers.hanchao.designpattern.adapter.adapter.V220ToV5Adapter:42 - 进行电压转换:220 --> 5
2019-07-09 13:01:44,986 INFO [main-1] pers.hanchao.designpattern.adapter.adapter.V220ToV5Adapter:43 - 转换之后的电源为:5
2019-07-09 13:01:44,986 INFO [main-1] pers.hanchao.designpattern.adapter.Phone:19 - 2.当前电压 : 5
2019-07-09 13:01:44,986 INFO [main-1] pers.hanchao.designpattern.adapter.Phone:20 - 3.进行充电 ...
该栗子UML图:
注:该栗子摘于博客地址:https://blog.csdn.net/hanchao5272/article/details/96484044