设计模式之适配器模式
适配器模式也叫包装器,属于结构型模式;就是把一个类的接口变换成客户端所期待的另一种接口,从而使原本因接口不匹配而无法在一起共组的两个类能够在一起工作,适配器模式的主要目的就是兼容性。适配器模式主要分为两类:类适配器模式,对象适配器模式。
都知道中国的生活用电电压是220V,而我们的智能手机充电器的输出电压是5V,那么手机充电器就是一个把220V高压交流电转为低压直流电的一个适配器。在本模式中,就使用这个来作为例子。
类适配器模式:
类适配器模式就是把被适配的类的API转换成为目标类的API。
类适配器模式的UML类图如下:
这种模式所涉及到目标角色、源角色、适配器角色以下几种角色:
- 目标角色:这就是所期待得到的角色。由于这里讨论的是类适配器模式,所以目标角色不可以是类,应该是一个接口
- 源角色:需要适配的接口
- 适配器角色:适配器角色是本模式的核心,适配器把源接口转换成目标接口。所以这一角色必须是一个具体的类
源角色:
package com.charon.adapter;
/**
* @className: Voltage220V
* @description: 源适配角色,220v电压
* @author: charon
* @create: 2022-03-14 23:12
*/
public class Voltage220V {
public int output220V(){
int voltage = 220;
System.out.println("电压 " + voltage + " 伏");
return voltage;
}
}
目标角色:
package com.charon.adapter;
/**
* @className: Voltage5V
* @description: 5v的适配接口
* @author: charon
* @create: 2022-03-14 23:09
*/
public interface Voltage5V {
/**
* 输出5V电压
* @return
*/
public int output5V();
}
适配器角色:
package com.charon.adapter;
/**
* @className: VoltageAdaptor
* @description: 电压适配器角色
* @author: charon
* @create: 2022-03-15 21:36
*/
public class VoltageAdaptor extends Voltage220V implements Voltage5V {
@Override
public int output5V() {
int voltage = output220V();
return voltage / 44;
}
}
使用者:
package com.charon.adapter;
/**
* @className: Phone
* @description: 使用者
* @author: charon
* @create: 2022-03-15 21:37
*/
public class Phone {
public static void main(String[] args) {
Phone phone = new Phone();
phone.charging(new VoltageAdaptor());
}
public void charging(Voltage5V voltage5V){
if(5 == voltage5V.output5V()){
System.out.println("电压为5V,可以进行充电~~~");
}else if(voltage5V.output5V() > 5){
System.out.println("电压大于5V,不可以进行充电~~~");
}
}
}
类适配器模式优缺点:
- 由于适配器类是源的子类,因此可以在适配器类中重写源角色的一些方法
- 由于只引进一个适配器类,因此只有一个路线到达目标类,使问题得到简化
- 正是由于适配器类是源角色的子类,而java是单继承的,如果有多个源需要适配,那这种方式就太过于繁琐了
对象适配器模式:
与类适配器模式一样,对象适配器模式是把被适配的类的API转换成目标类的API,与类适配器模式不同的是,对象适配器模式不是使用继承关系连接到Adaptee(源角色)类的,而是使用委派关系连接到Adaptee(源角色)类。即根据“合成复用原则”中的使用关联关系代替继承关系。
对象适配器模式的UML类图如下:
对象适配器模式涉及到的角色和类适配器涉及到的角色一致。
相应的代码也差不多,唯一的区别在于适配器角色:
package com.charon.adapter;
/**
* @className: VoltageAdaptor1
* @description: 对象适配器模式
* @author: charon
* @create: 2022-03-15 22:04
*/
public class VoltageAdaptor1 implements Voltage5V{
private Voltage220V voltage220V;
/**
* 通过构造器传入一个Voltage220V的对象实例
* @param voltage220V
*/
public VoltageAdaptor1(Voltage220V voltage220V) {
this.voltage220V = voltage220V;
}
@Override
public int output5V() {
int outputV = 0;
if(null != voltage220V){
int inputV = voltage220V.output220V();
outputV = inputV / 44;
}
return outputV;
}
}
测试:
package com.charon.adapter;
/**
* @className: Phone
* @description: 使用者
* @author: charon
* @create: 2022-03-15 21:37
*/
public class Phone {
public static void main(String[] args) {
Phone phone = new Phone();
phone.charging(new VoltageAdaptor1(new Voltage220V()));
}
public void charging(Voltage5V voltage5V){
if(5 == voltage5V.output5V()){
System.out.println("电压为5V,可以进行充电~~~");
}else if(voltage5V.output5V() > 5){
System.out.println("电压大于5V,不可以进行充电~~~");
}
}
}
打印:
电压 220 伏
电压为5V,可以进行充电~~~
对象适配器模式的优缺点:
- 一个适配器可以把多种不同的源角色适配到同一个目标角色,换言之,同一个适配器可以把源类和它的子类都适配到目标接口
- 与类适配器模式相比,要想置换源类的方法就不容易,如果一个要置换掉源类的一个或多个方法,就只好先做一个源类的子类,将源类的方法置换掉,然后再把源类的子类当作真正的源进行适配
- 虽然要想置换源类的方法不容易,但是要想增加一些新的方法则方便的很,而且新增加的方法可同时适用于所有的源
在什么情况下使用适配器模式:
- 系统需要使用现有的类,而此类的接口不符合系统的需要
- 想要建立一个可以重复使用的类,用于与一些彼此之间没有太大关联的一些类,包括一些可能在将来引进的类一起工作,这些源类不一定有很复杂的接口
- 对于对象适配器模式而言,在设计里。需要改变多个已有的子类的接口,如果使用类的适配器模式,就要针对每一个子类做一个适配器类,而这不太实际
本文版权归Charon和博客园共有,原创文章,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。