超级链接: Java常用设计模式的实例学习系列-绪论
参考:《HeadFirst设计模式》
适配器模式是一种结构型
模式。
适配器模式:将一个类的接口转换成客户期望的另一个接口,使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。
下面以一张经典的图来描述适配器模式:
本文以电压适配器
为场景来学习适配器模式
:
Phone
电需要的电压是5V的。PortableBatteryPower
提供的电源是5V的,所以手机可以直接通过充电宝进行充电。HouseholdPower
提供的电压是220V的,所有手机不能直接通过家用电源进行充电。假定现在有充电宝,则可以直接进行手机充电。
分析上面的场景,其实手机充电依赖的不仅仅是充电宝,而是依赖的一种5V的电源。
所以,首先,我们定义一个5V的电源,并以充电宝作为一种实现。
5V电源:接口:V5Power
/**
* 5V的电源
*
* @author hanchao
*/
public interface V5Power {
/**
* 获取名称
*/
String getName();
/**
* 获取电压
*/
Integer getVoltage();
}
5V电源:实现:充电宝:PortableBatteryPower
/**
* 充电宝
*
* @author hanchao
*/
public class PortableBatteryPower implements V5Power {
@Override
public String getName() {
return "充电宝";
}
@Override
public Integer getVoltage() {
return 5;
}
}
然后,定义一个手机Phone
,它具有充电功能batteryCharge()
,其能接受的参数是V5Power
类型的。
/**
* 手机
*
* @author hanchao
*/
@Slf4j
public class Phone {
/**
* 充电
*/
public void batteryCharge(V5Power v5Power) {
log.info("1.连接电源 ==> " + v5Power.getName());
log.info("2.当前电压 : " + v5Power.getVoltage());
log.info("3.进行充电 ... ");
}
}
最后,我们写一段测试代码:AdapterDemo
public static void main(String[] args) {
//首先,需要一部手机
Phone phone = new Phone();
log.info("如果有充电宝,则直接用它充电");
V5Power v5Power = new PortableBatteryPower();
phone.batteryCharge(v5Power);
}
运行结果
2019-07-09 12:44:03,556 INFO [main-1] pers.hanchao.designpattern.adapter.AdapterDemo:22 - 如果有充电宝,则直接用它充电
2019-07-09 12:44:03,560 INFO [main-1] pers.hanchao.designpattern.adapter.Phone:19 - 1.连接电源 ==> 充电宝
2019-07-09 12:44:03,560 INFO [main-1] pers.hanchao.designpattern.adapter.Phone:20 - 2.当前电压 : 5
2019-07-09 12:44:03,560 INFO [main-1] pers.hanchao.designpattern.adapter.Phone:21 - 3.进行充电 ...
假定现在只有家用电源,则不能直接进行手机充电。
分析上面的场景,其实手机不仅仅不能通过家用电源直接充电,所有220V的电源都不能直接用于手机充电。
所以,我们定义一个220V的电源,并以家用电源作为一种实现。
220V电源:接口:V220Power
/**
* 220V的电源
*
* @author hanchao
*/
public interface V220Power {
/**
* 获取名称
*/
String getName();
/**
* 获取电压
*/
Integer getVoltage();
}
220V电源:实现:家用电源:HouseholdPower
/**
* 家用电源
*
* @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
,这个适配器应该实现以下两个功能:
V5Power
的,如此才能作为batteryCharge()
方法的参数。所以有:Adapter implements V5Power
。V220Power
的对象,如此才能实现最初的目的:使用V220的电源。所以有成员变量:V220Power v220Power
。上面所描述的,其实就是开始的示例图中的那句话:适配器本身包含接口乙,并实现了接口甲。
根据这个思路,很容易实现适配器代码。
适配器:V220=>V5:V220ToV5Adapter
/**
* USB接口转换器
*
* 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类图来总结本文的电压适配器场景以及适配器模式。
适配器模式遵循了一条很重要的OOP原则,那就是:多用组合,少用继承
。
适配器模式,能够有效的解决接口不兼容
问题。
适配器模式的优点:
不兼容接口
与客户端
解耦,两者都不必修改原有代码。