适配器模式
概述
适配器模式(Adapter Pattern)将某个类的接口转换成客户端期望的另一个接口表示,主的目的是兼容性,让原本因接口不匹配不能一起工作的两个类可以协同工作。其别名为包装器(Wrapper)
适配器模式属于结构型模式
主要分为三类:类适配器模式、对象适配器模式、接口适配器模式
概述:将一个类的接口转换成客户希望的另外一个接口,使得原本由于接口不兼容而不能一起工作的那些类能一起工作。
核心: 兼容,转换;让接口不兼容的类可以兼容,让类与类之间可以协调工作,当被适配的类变化的时候,通过适配器模式也会使调用适配器类的方法发生变化
工作原理
- 适配器模式:将一个类的接口转换成另一种接口.让原本接口不兼容的类可以兼容
- 从用户的角度看不到被适配者,是解耦的
- 用户调用适配器转化出来的目标接口方法,适配器再调用被适配者的相关接口方法
- 用户收到反馈结果,感觉只是和目标接口交互。
应用场景
- 当你希望使用某个类, 但是其接口与其他代码不兼容时, 可以使用适配器类。
- 如果您需要复用这样一些类, 他们处于同一个继承体系, 并且他们又有了额外的一些共同的方法, 但是这些共同的方法不是所有在这一继承体系中的子类所具有的共性。
- 使用第三方提供的组件,但组件接口定义和自己要求的接口定义不同
SpringMVC框架中适配器模式
- SpringMvc 中 的HandlerAdapter, 就使用了适配器模式
- SpringMVC处理请求的流程
- 使用HandlerAdapter 的原因分析:
可以看到处理器的类型不同,有多重实现方式,那么调用方式就不是确定的,如果需要直接调用
Controller方法,需要调用的时候就得不断是使用if else来进行判断是哪一种子类然后执行。那么
如果后面要扩展Controller,就得修改原来的代码,这样违背了OCP原则。
优缺点
优点:
- 单一职责原则_你可以将接口或数据转换代码从程序主要业务逻辑中分离。
- 开闭原则。 只要客户端代码通过客户端接口与适配器进行交互, 你就能在不修改现有客户端代码的情况下在程序中添加新类型的适配器。
缺点:
- 代码整体复杂度增加, 因为你需要新增一系列接口和类。 有时直接更改服务类使其与其他代码兼容会更简单。
类适配器模式
定义适配器Adapter类,通过继承 src类,实现 dst 类接口,完成src->dst的适配。
- Java是单继承机制,所以类适配器需要继承src类这一点算是一个缺点, 因为这要求dst必须是接口,有一定局限性;
- src类的方法在Adapter中都会暴露出来,也增加了使用的成本。
- 由于其继承了src类,所以它可以根据需求重写src类的方法,使得Adapter的灵活性增强了。
类图
示例代码
使用类适配器模拟5V电压的手机充电
public class VoltageAdapter extends Voltage220V implements Voltage5V{
public int outPut5VVoltage(){
int originalVoltage = outPut220VVoltage();
return originalVoltage/44;
}
}
public class Voltage220V {
private int voltage = 220;
public int outPut220VVoltage(){
return voltage;
}
}
public interface Voltage5V {
int outPut5VVoltage();
}
public class Phone {
public void charge(Voltage5V voltage5V){
if (voltage5V != null) {
int i = voltage5V.outPut5VVoltage();
System.out.println("电压为"+i+"V开始给手机充电");
}
}
}
public class Client {
public static void main(String[] args) {
Phone phone = new Phone();
phone.charge(new VoltageAdapter());
}
}
对象适配器模式
基本思路和类的适配器模式相同,只是将Adapter类作修改,不是继承src类,而是持有src类的实例,以解决兼容性的问题。 即:持有src类,实现dst类接口,完成src->dst的适配 根据“合成复用原则”,在系统中尽量使用关联关系(聚合)来替代继承关系。
对象适配器模式是适配器模式常用的一种
对象适配器和类适配器其实算是同一种思想,只不过实现方式不同。
根据合成复用原则,使用组合替代继承, 所以它解决了类适配器必须继承src的局限性问题,也不再要求dst必须是接口。 使用成本更低,更灵活。
类图
示例代码![在这里插入图片描述](https://img-blog.csdnimg.cn/20210617092909567.jpg?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80OTU2MTQ0NQ==,size_16,color_FFFFFF,t_70#pic_center)
public record VoltageAdapter(Voltage220V voltage220V) implements Voltage5V {
@Override
public int out5VVoltage() {
if (voltage220V != null) {
return voltage220V.outPut220VVoltage() / 44;
}
return 0;
}
}
public class Voltage220V {
public int outPut220VVoltage(){
return 220;
}
}
public interface Voltage5V {
int out5VVoltage();
}
public class Phone {
public void charge(Voltage5V voltage5V){
if (voltage5V.out5VVoltage() == 5){
System.out.println("电压为5V,可以充电,开始给手机充电");
}
}
}
public class Client {
public static void main(String[] args) {
Phone phone = new Phone();
phone.charge(new VoltageAdapter(new Voltage220V()));
}
}
接口适配器模式
当不需要全部实现接口提供的方法时,可先设计一个抽象类实现接口,并为该接口中每个方法提供一个默认实现(空方法),
那么该抽象类的子类可有选择地覆盖父类的某些方法来实现需求
适用于一个接口不想使用其所有的方法的情况
类图
示例代码
public abstract class VoltageAdapter implements Voltage{
protected VoltageAdapter() {}
public void outPut220VVoltage(){}
public void outPut5VVoltage(){}
public void outPut380VVoltage(){}
}
public interface Voltage {
void outPut220VVoltage();
void outPut5VVoltage();
void outPut380VVoltage();
}
public class Phone {
public void charge(){
new VoltageAdapter(){
public void outPut5VVoltage(){
System.out.println("电压为5V,开始给手机充电");
}
}.outPut5VVoltage();
}
}
public class Client {
public static void main(String[] args) {
Phone phone = new Phone();
phone.charge();
}
}