【Java设计模式】结构型设计模式-适配器模式(六)
适配器模式
适配器模式(Adapter Pattern)将某个类的接口转换成客户端期望的另一个接口表示, 主要的目的是兼容性,让原本因接口不匹配不能一起工作的两个类可以协同工作,其别名为包装器(Wrapper);适配器模式属于结构型模式;主要分为三类:类适配器模式、对象适配器模式、接口适配器模式。
进一步阐述:
- 适配器模式:将一个类的接口转换成另一种接口让原本接口不兼容的类可以相互兼容使用。
- 从用户的角度看不到被适配者的,因为适配器做了被适配者和使用者的解耦。
- 用户调用适配器转化出来的目标接口的方法,适配器再调用被适配者的相关接口方法。
- 用户收到反馈结果,感觉只是和目标接口交互,没有感觉到有适配器的存在。
适配器模式包含三种角色:
- Target(目标接口):客户端所需要的接口,可以是接口或抽象类,也可以是实体类。
- Adaptee(需要适配的类):被适配者,也就是想要新加入使得目标接口可用的类。
- Adapter(适配器):把原接口转化成目标接口的类。
案例:我们以电脑通过USB接口接入各种设备为例,USB接口类就是目标接口,ApplePhone就是需要适配的类,USBAdapter类就是适配器。
Computer电脑类:
/**
* 电脑类(相当于使用方即客户端)
* 只有USB接口
*/
public class Computer {
/**
* 使用某USB设备方法
*/
public String useElectronicEquipment(USB usb) {
return usb.provideUsbSomething();
}
public static void main(String[] args) {
//创建电脑使用电脑的功能
Computer computer = new Computer();
//使用移动硬盘
System.out.println(computer.useElectronicEquipment(new MobileHardDisk()));
}
}
USB接口类:
/**
* USB接口(相当于提供方及目标接口)
*/
public interface USB {
/**
* 提供相关功能方法
*/
String provideUsbSomething();
}
移动硬盘MobileHardDisk类:
/**
* 移动硬盘
*/
public class MobileHardDisk implements USB {
@Override
public String provideUsbSomething() {
return "提供移动硬盘的功能";
}
}
由上可以看到,如果我们需要接入其他设配只需要接入的设备去实现USB接口,在原有Computer类中进行创建和使用即可,但是假如现在我有一个苹果手机,但该手机并不能直接接入USB接口,在生活中我们是通过转接头等方式来进行接入,那么类适配器模式就等于是这个转接头。
类适配器模式
UML类图:
苹果手机Lightning接口:
/**
* 苹果手机充电接口
*/
public interface Lightning {
/**
* 提供苹果手机相关功能方法
*/
String provideLightningSomething();
}
苹果手机ApplePhone实现类:
/**
* 苹果手机(相当于需要适配的类即Adaptee)
*/
public class ApplePhone implements Lightning {
@Override
public String provideLightningSomething() {
return "提供苹果手机相关功能";
}
}
USB适配器USBAdapter类:
/**
* USB接口适配器(相当于一个多功能USB转接头即Adapter)
* 这种使用继承的方式就是类适配器模式
*/
public class USBAdapter extends ApplePhone implements USB{
@Override
public String provideUsbSomething() {
return provideLightningSomething();
}
}
电脑类Computer类改造使用:
/**
* 电脑类(相当于使用方即客户端)
* 只有USB接口
*/
public class Computer {
/**
* 使用某USB设备方法
*/
public String useElectronicEquipment(USB usb) {
return usb.provideUsbSomething();
}
public static void main(String[] args) {
//创建电脑使用电脑的功能
Computer computer = new Computer();
//使用移动硬盘
System.out.println(computer.useElectronicEquipment(new MobileHardDisk()));
//使用苹果手机
System.out.println(computer.useElectronicEquipment(new USBAdapter()));
}
}
以上就是一个类适配器的简单案例,但是有一些缺陷:
-
Java 是单继承机制,所以类适配器需要继承 ApplePhone 类这一点算是一个缺点,因为这要求 USB 必须是接口,有一定局限性。
-
ApplePhone 类的方法在 Adapter 中都会暴露出来,也增加了使用的成本。
-
由于其继承了 ApplePhone 类,所以它可以根据需求重写 ApplePhone 类的方法,使得 Adapter 的灵活性增强了。但是ApplePhone是一个实体类,如果重写其已经实现的方法那么就会违反里式替换原则。
对象适配器模式
UML类图:
苹果手机Lightning接口:
/**
* 苹果手机充电接口
*/
public interface Lightning {
/**
* 提供苹果手机相关功能方法
*/
String provideLightningSomething();
}
苹果手机ApplePhone实现类:
/**
* 苹果手机(相当于需要适配的类即Adaptee)
*/
public class ApplePhone implements Lightning {
@Override
public String provideLightningSomething() {
return "提供苹果手机相关功能";
}
}
USB适配器USBAdapter类:
/**
* USB接口适配器(相当于一个多功能USB转接线)
* 这种使用组合的方式就是对象适配器模式
*/
public class USBAdapter1 implements USB {
private ApplePhone applePhone;
public USBAdapter1(ApplePhone applePhone) {
this.applePhone = applePhone;
}
@Override
public String provideUsbSomething() {
return applePhone.provideLightningSomething();
}
}
电脑类Computer类改造使用:
/**
* 电脑类(相当于使用方即客户端)
* 只有USB接口
*/
public class Computer {
/**
* 使用某USB设备方法
*/
public String useElectronicEquipment(USB usb) {
return usb.provideUsbSomething();
}
public static void main(String[] args) {
//创建电脑使用电脑的功能
Computer computer = new Computer();
//使用移动硬盘
System.out.println(computer.useElectronicEquipment(new MobileHardDisk()));
//使用苹果手机
System.out.println(computer.useElectronicEquipment(new USBAdapter()));
//使用苹果手机(对象适配器)
System.out.println(computer.useElectronicEquipment(new USBAdapter1(new ApplePhone())));
}
}
以上就是一个对象适配器的简单案例,它有如下的优点:
-
基本思路和类的适配器模式相同,只是将 Adapter 类做修改,不是继承 ApplePhone 类,而是持有 ApplePhone 类的实例,以解决兼容性的问题。 即:持有 ApplePhone 类,实现 USB 接口,完成 ApplePhone到USB 的适配。
-
根据“ 合成复用原则”,在系统中尽量使用 关联关系(组合)来替代继承关系。
-
对象适配器模式是适配器模式运用最多的一种。
接口适配器模式
接口适配器模式就是说一个接口含有多个抽象方法,我们通过一个抽象类来实现其具体的接口,实际在使用时可以根据要使用的方法来进行适配,这种方式的好处是在于,如果我们采用一个类直接去实现一个接口,那么需要覆盖所有的抽象方法,但可能在使用方使用时关心的是某一个方法,所以我们以抽象类的方式呈现的这种方式可以不需要我们去覆盖不关注的方法。
/**
* 接口适配器模式,也叫缺省适配器模式
*/
public class InterfaceAdapter {
public static void main(String[] args) {
//在某处需要使用到TestInterface的实现类
test(new AbsClass() {
@Override
public void testMethod3() {
super.testMethod3();
}
});
}
public static void test(TestInterface ti) {
ti.testMethod3();
}
}
//Target接口
interface TestInterface {
void testMethod1();
void testMethod2();
void testMethod3();
void testMethod4();
void testMethod5();
}
//适配器角色
abstract class AbsClass implements TestInterface {
@Override
public void testMethod1() {
}
@Override
public void testMethod2() {
}
@Override
public void testMethod3() {
}
@Override
public void testMethod4() {
}
@Override
public void testMethod5() {
}
}
值得注意的是:在Java8之后由于加入了default关键字,允许接口中出现默认方法,其实可以把它看做是接口适配器模式的一种简化
转载自:https://juejin.cn/post/7352438029199589395