08.适配器模式
概念:
将一个类的接口转化成用户需要的另外一个接口。适配器模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。
适配器模式可以分为类适配器和对象适配器两种,区别在于适配器角色对应被适配角色的适配是通过继承还是组合来实现的。由于Java不支持多继承,而且会破坏封装性,所有我们提倡多用组合少用继承。
用途:
特定型号的手机只能使用特定型号的充电器充电。比如Iphone6手机只能使用Lightning接口的充电器充电。但是,如果我们身边只有一条安卓的Micro Usb充电线的话,我们能不能为苹果手机充电呢?答案是肯定的,只要有一个适配器就可以了。
在程序设计过程中我们可能也遇到类似的场景:
1、系统需要使用现有的类,而此类的接口不符合系统的需要。
2、想要建立一个可以重复使用的类,用于与一些彼此之间没有太大关联的一些类,包括一些可能在将来引进的类一起工作,这些源类不一定有一致的接口。
3、通过接口转换,将一个类插入另一个类系中。(比如老虎和飞禽,现在多了一个飞虎,在不增加实体的需求下,增加一个适配器,在里面包容一个虎对象,实现飞的接口。)
以上场景都适合使用适配器模式。
实现方式
适配器模式包含以下角色:
Target:目标抽象类
Adapter:适配器类
Adaptor:适配者类
Client:客户类
我们来针对使用适配器让安卓充电器给苹果手机充电这个例子。
(1)先定义两个充电器接口
/**
* 安卓MicroUsb —— 充电器接口
*/
public interface MicroUsbInterface {
public void chargeWithMicroUsb();
}
/**
* 苹果Lightning —— 充电器接口
*/
public interface LightningInterface {
public void chargeWithLightning();
}
(2)具体实现类:
/**
* 安卓设备充电器 —— 充电器
*/
public class AndroidCharger implements MicroUsbInterface {
@Override
public void chargeWithMicroUsb() {
System.out.println("使用MicroUsb型号的充电器充电。。。。。");
}
}
/**
* 苹果设备的充电器 —— 充电器
*/
public class AppleCharger implements LightningInterface {
@Override
public void chargeWithLightning() {
System.out.println("使用Lightning型号的充电器充电。。。。");
}
}
(3)定义两台手机:
/**
* HWp10pro —— 手机
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class HWP10pro {
private MicroUsbInterface microUsbInterface;
public void charge() {
System.out.println("开始给我的HWp10pro手机充电。。。");
microUsbInterface.chargeWithMicroUsb();
System.out.println("结束给我的HWp10pro手机充电。。。");
}
}
/**
* 苹果6Puls —— 手机
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Iphone6Plus {
private LightningInterface lightningInterface;
public void charge() {
System.out.println("开始给我的IphonePlus手机充电。。。");
lightningInterface.chargeWithLightning();
System.out.println("结束给我的IphonePlus手机充电。。。");
}
}
(4)定义适配器
/**
* MicroUsb接口转成Lightning接口 —— 适配器
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Adapter implements LightningInterface {
private MicroUsbInterface microUsbInterface;
@Override
public void chargeWithLightning() {
microUsbInterface.chargeWithMicroUsb();
}
}
(5)测试类
public class Main {
public static void main(String[] args) {
final Iphone6Plus iphone6Plus = new Iphone6Plus(new AppleCharger());
iphone6Plus.charge();
System.out.println("-----------------");
final HWP10pro HWP10pro = new HWP10pro(new AndroidCharger());
HWP10pro.charge();
System.out.println("-----------------");
final Adapter adapter = new Adapter(new AndroidCharger());
final Iphone6Plus iphone6Plus1 = new Iphone6Plus();
iphone6Plus1.setLightningInterface(adapter);
iphone6Plus1.charge();
}
}
输出
开始给我的IphonePlus手机充电。。。
使用Lightning型号的充电器充电。。。。
结束给我的IphonePlus手机充电。。。
-----------------
开始给我的HWp10pro手机充电。。。
使用MicroUsb型号的充电器充电。。。。。
结束给我的HWp10pro手机充电。。。
-----------------
开始给我的IphonePlus手机充电。。。
使用MicroUsb型号的充电器充电。。。。。
结束给我的IphonePlus手机充电。。。
优缺点:
优点:
将目标类和适配者类解耦,通过引入一个适配器类来重用现有的适配者类,而无须修改原有代码。
增加了类的透明性和复用性,将具体的实现封装在适配者类中,对于客户端类来说是透明的,而且提高了适配者的复用性。
灵活性和扩展性都非常好,通过使用配置文件,可以很方便的更换适配器,也可以在不修改原有代码的基础上添加新的适配器类,完全符合"开闭原则"。
缺点:
过多使用适配器,会让系统非常凌乱,不易整体进行把握。比如,明明看到调用的是A接口,其实内部被适配成了B接口的实现。因此如果不是很有必要,可以不适应适配器,而是直接对系统进行重构。
对于类适配器而言,由于Java最多继承一个类,所以最多只能适配一个适配者类,而且目标类必须是抽象类。