阅读 136

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等文章, 可能有你想要了解的技能知识点哦~

文章分类
代码人生
文章标签