DesignPattern - 适配器模式结构型
Posted GitLqr
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了DesignPattern - 适配器模式结构型相关的知识,希望对你有一定的参考价值。
欢迎关注微信公众号:FSA全栈行动 👋
一、适配器模式介绍
适配器模式(Adapter Pattern)属于结构型模式,作为两个不兼容的接口之间的桥梁。
- 常见的几类适配器
- 接口的适配器模式【空实现】:不想实现一个接口中所有的方法时,可以创建一个 Adapter,实现所有方法,在写别的类的时候,继承这个 Adapter 类即可。
- 类的适配器模式【继承(旧) + 实现(新)】:想将一个类转换成满足另一个新接口的类时,可以使用类的适配器模式,创建一个新类,继承原有的类,实现新的接口即可。
- 对象的适配器模式【组合】:想将一个对象转换成满足另一个新接口的对象时,可以创建一个适配器类,持有原类的一个实例,在适配器类的方法中,调用实例的方法就行。
- 应用场景
- 电脑需要读取内存卡的数据,读卡器就是适配器
- 日常使用的转换头,如电源转换头,电压转换头
- 系统需要使用现在的类,而这些类的接口不符合系统的需要(如:JDK 中 InputStreamReader 就是适配器)
- JDBC 使用的就是适配器模式,jDBC 给出一个客户端通用的抽象接口,每一个具体数据库厂商,如 SQL Server、Oracle、mysql 等,会开发对应的 JDBC 驱动,这个 JDBC 驱动就是一个介于 JDBC 接口和数据库引擎接口之间的适配器软件。
- 优点
- 可以让任何两个没有关联的类一起运行,使得原本由于接口不兼容而不能一起工作的那些类可以一起工作
- 增加灵活度,提高复用性,适配器类可以在多个系统使用,符合开闭原则
- 缺点
- 整体类的调用链路增加,本来 A 可以直接调用 C,使用适配器后,是 A 调用 B,B 再调用 C
补充:适配器模式用于设计完成之后,发现类、接口之间无法一起工作,需要进行填坑。
二、适配器模式代码实现
1、接口适配器模式
有些接口中有多个抽象方法,当我们写该接口的实现类时,必须实现该接口的所有方法,有时会觉得比较冗余,因为并不是所有的方法都是我们需要的,只需要实现部分接口就可以了。
创建支付网关接口:
/**
* 支付网关接口
*
* @author GitLqr
*/
public interface IPayGateway {
/**
* 下单
*/
void order();
/**
* 退款
*/
void refund();
/**
* 查询
*/
void query();
/**
* 发红包
*/
void sendRedPack();
...
}
创建接口适配器类:
/**
* 接口适配器:提供所有接口的默认实现
*
* @author GitLqr
*/
public class PayGatewayAdapter implements IPayGateway {
@Override
public void order() {
}
@Override
public void refund() {
}
@Override
public void query() {
}
@Override
public void sendRedPack() {
}
}
创建具体业务类:
/**
* 视频VIP订购:只有订购和退款功能
*
* @author GitLqr
*/
public class VideoVipOrder extends PayGatewayAdapter {
@Override
public void order() {
System.out.println("视频VIP 订购成功");
}
@Override
public void refund() {
System.out.println("视频VIP 退款成功");
}
}
说明:相比于实现 IPayGateway 接口,继承 PayGatewayAdapter 适配器类,可以让 VideoVipOrder 中代码简洁不少。
2、类的适配器模式
想将一个类转换成满足另一个新接口的类时,可以使用类的适配器模式,创建一个新类,继承原有的类,实现新的接口即可。
创建 旧类:
说明:【旧类】对应的是工程中原本就存在的类,能够稳定运行,但是不支持一些新功能。实际开发中,这些旧类实现可能相当复杂(可能是屎山),不能轻易改动!!
/**
* 旧类:端口,只能支持usb
*
* @author GitLqr
*/
public class Port {
public void usb(Object usbDevice) {
System.out.println("插入 usb 设备");
}
}
创建 新功能接口:
说明:该【新功能接口】一般拥有 旧类 中的方法,方便后续面向接口编程。
/**
* 新接口:需要支持旧端口类型(usb)的同时,支持更多的新端口类型(如 typec、usb4)
*
* @author GitLqr
*/
public interface INewPort {
void usb(Object usbDevice);
void typec(Object typecDevice);
void usb4(Object usb4Device);
}
创建 新类:
说明:【新类】需要继承【旧类】,同时实现【新功能接口】
/**
* 新类:端口适配器【扩展坞】
*
* @author GitLqr
*/
public class PortAdapter extends Port implements INewPort {
@Override
public void typec(Object typecDevice) {
System.out.println("插入 type-c 设备");
}
@Override
public void usb4(Object usb4Device) {
System.out.println("插入 雷电4 设备");
}
}
使用:
public static void main(String[] args) {
...
INewPort newPort = new PortAdapter();
newPort.usb(usbDevice); // 老功能 也能正常使用
newPort.typec(typecDevice);
newPort.usb4(usb4Device);
}
3、对象的适配器模式
想将一个对象转换成满足另一个新接口的对象时,可以创建一个适配器类,持有原类的一个实例,在适配器类的方法中,调用实例的方法就行。
对象的适配器更像是一种包装(或增强),实际功能还需要借助原对象来执行处理,就比如充电器插头问题,插头转换器只是改变了充电器插头的类型,实际上给手机充电的,还是充电器本身。
创建 充电器类:
/**
* 充电器
*
* @author GitLqr
*/
public class Charger {
void charge() {
System.out.println("充电中...");
}
}
创建 新接口(支持多种插头转换):
/**
* 接口:各式插头
*
* @author GitLqr
*/
public interface IPlugConverter {
/**
* 双脚插头充电
*/
void chargeOnTwoPin();
/**
* 三脚插头充电
*/
void chargeOnThreePin();
/**
* 三脚插头充电(港版插座)
*/
void chargeOnThreePinHK();
}
创建 满足 新接口 的 适配器类:
/**
* 充电器插头适配器
*
* @author GitLqr
*/
public class ChargerPlugAdapter implements IPlugConverter {
private Charger charger;
public ChargerPlugAdapter(Charger charger) {
super();
this.charger = charger;
}
@Override
public void chargeOnTwoPin() {
charger.charge();
}
@Override
public void chargeOnThreePin() {
System.out.println("使用三脚插头");
charger.charge();
}
@Override
public void chargeOnThreePinHK() {
System.out.println("使用港版三脚插头");
charger.charge();
}
}
如果文章对您有所帮助, 请不吝点击关注一下我的微信公众号:FSA全栈行动, 这将是对我最大的激励. 公众号不仅有android技术, 还有ios, Python等文章, 可能有你想要了解的技能知识点哦~
以上是关于DesignPattern - 适配器模式结构型的主要内容,如果未能解决你的问题,请参考以下文章