文章目录
- 基本介绍
- 一、类的适配器
- 二、对象适配器
- 三、接口适配器
- 总结
基本介绍
生活中有很多例子:
- 不同国家的插座接口不同,需要转换器;
- 家用电源220V,手机只接受5V充电,需要转换器;
- 读卡器,拓展坞。。。
定义:
适配器模式的主要作用是将一个类的接口转换成客户希望的另外一个接口,使得原本由于接口不兼容而不能一起工作的那些类能一起工作。
适配器模式分为类适配器模式和对象适配器模式,前者类之间的耦合度比后者高,且要求程序员了解现有组件库中的相关组件的内部结构,所以应用相对较少些。
结构:
适配器模式(Adapter)包含以下主要角色:
- 目标(Target)接口: 当前系统业务所期待的接口,它可以是抽象类或接口;
- 适配者(Adaptee)类: 它是被访问和适配的现存组件库中的组件接口;
- 适配器(Adapter)类: 它是一个转换器,通过继承或引用适配者的对象,把适配者接口转换成目标接口,让客户按目标接口的格式访问适配者。
一、类的适配器
实现方式:定义一个适配器类来实现当前系统的业务接口,同时又继承现有组件库中已经存在的组件。
【例】手机充电器
家用电源220V,手机只接受5V充电,要想给手机充电,我们得需要一个转换器。
家用电源【适配者类】:
public class Voltage220V {
public Integer output22V() {
return 220;
}
}
目标接口:
//充电器接口
public interface IVoltage5V {
Integer output5V();
}
//给个实现类
public class Voltage5V implements IVoltage5V {
@Override
public Integer output5V() {
return 5;
}
}
适配器类:
public class VoltageAdapter extends Voltage220V implements IVoltage5V {
@Override
public Integer output5V() {
return 5;
}
}
手机类:
public class Phone {
public void charging(IVoltage5V iVoltage5V) {
if(iVoltage5V.output5V() == 5) {
System.out.println("电压5V, 正在充电。。。");
} else {
System.out.println("只能使用5V电压充电。。。");
}
}
}
测试:
public class Client {
public static void main(String[] args) {
Phone phone = new Phone();
System.out.println("===直接使用5V电源充电===");
phone.charging(new Voltage5V());
System.out.println("===使用类适配器充电===");
phone.charging(new VoltageAdapter());
}
}
小结:
- Java 是单继承机制,所以类适配器需要继承
src
一个缺点,因为这要求dst
必须是接口,有一定局限性; src
类的方法在 Adapter 中都会暴露出来,也增加了使用的成本;- 由于其继承了
src
类,所以它可以根据需求重写src
类的方法,使得Adapter
的灵活性增强了。
二、对象适配器
- 对象适配器模式可釆用将现有组件库中已经实现的组件引入适配器类中,该类同时实现当前系统的业务接口;
- 基本思路和类的适配器模式相同,只是将
Adapter
类作修改,不是继承src
类,而是持有src
类的实例,以解兼容性的问题。 即:持有src
类,实现dst
类接口,完成src
->dst
的适配; - 根据“合成复用原则”,在系统中尽量使用关联关系(聚合)来替代继承关系;
- 对象适配器模式是适配器模式常用的一种。
使用对象适配器将上述案例做以修改后,UML类图为:
家用电源【适配者类】:
public class Voltage220V {
public Integer output220V() {
return 220;
}
}
目标接口:
public interface IVoltage5V {
Integer output5V();
}
public class Voltage5V implements IVoltage5V {
@Override
public Integer output5V() {
return 5;
}
}
适配器类:
public class VoltageAdapter implements IVoltage5V {
private Voltage220V voltage220V;
public VoltageAdapter(Voltage220V voltage220V) {
this.voltage220V = voltage220V;
}
@Override
public Integer output5V() {
//适配规则
Integer v220 = voltage220V.output220V();
return v220 / 44;
}
}
public class Phone {
public void charging(IVoltage5V iVoltage5V) {
System.out.println("正在充电, 电压" + iVoltage5V.output5V() + "V");
}
}
测试:
public class Demo2 {
public static void main(String[] args) {
Phone phone = new Phone();
System.out.println("===直接使用5V电源充电===");
phone.charging(new Voltage5V());
System.out.println("===使用对象适配器充电===");
phone.charging(new VoltageAdapter(new Voltage220V()));
}
}
- 对象适配器和类适配器其实算是同一种思想,只不过实现方式不同。根据合成复用原则,使用组合替代继承,所以它解决了类适配器必须继承
src
的局限性问题,也不再要求dst
必须是接口; - 使用成本更低,更灵活。
三、接口适配器
- 适配器又叫缺省适配器模式;
- 核心思路:当不需要全部实现接口提供的方法时,可先设计一个抽象类实现接口,并为该接口中每个方法提供一个默认实现(空方法),那么该抽象类的子类可有选择地覆盖父类的某些方法来实现需求;
- 适用于一个接口不想使用其所有的方法的情况。
总结
结构:
- 类适配器:以类给到适配器,在 Adapter 里,就是将 src 当做类,继承;
- 对象适配器:以对象给到适配器,在 Adapter 里,将 src 作为一个对象,持有;
- 接口适配器:以接口给到适配器,在 Adapter 里,将 src 作为一个接口,实现。
优点:
-
适配器模式最大的作用还是将原本不兼容的接口融合在一起工作;
-
将目标类和适配者类解耦,通过引入一个适配器类来重用现有的适配者类,无须修改原有结构;
-
增加了类的透明性和复用性,将具体的业务实现过程封装在适配者类中,对于客户端类而言是透明的,而且提高了适配者的复用性,同一个适配者类可以在多个不同的系统中复用;
-
灵活性和扩展性都非常好,通过使用配置文件,可以很方便地更换适配器,也可以在不修改原有代码的基础上增加新的适配器类,完全符合“开闭原则”;
-
对象适配器避免了但继承的缺点,可以把多个不同的适配者适配到同一个目标。