定义
将一个接口转换成客户希望的另一个接口,使接口不兼容的那些类可以一起工作。
UML类图
类结构型模式
对象结构型模式
两种模式最大的区别在于适配器和适配者之间的关系不同,类适配器模式中适配器和适配者是继承关系,对象适配器模式中适配器和适配者之间是关联关系。
由于Java、C#等语言不支持多重类继承,因此类适配器的使用受到很多限制,例如如果目标抽象类Target不是接口,而是一个类,就无法使用类适配器;此外,如果适配者Adapter为最终(Final)类,也无法使用类适配器。
在Java等面向对象编程语言中,大部分情况下我们使用的是对象适配器,类适配器较少使用。
案例:监控摄像头集成
应急指挥系统需要集成监控摄像头,调用播放、停止、快进、查看历史等功能。
监控摄像头存在多个厂商,如大华、海康,每个厂商提供的sdk差异较大,例如播放操作,大华的方法名可能叫play,海康的方法名叫startPlay,并且日后可能增加新的厂商。
实现:使用适配器模式
1. 定义摄像头操作的统一接口
public interface CameraControl {
void play();
void stop();
void fastForward();
void viewHistory();
}
2. 各摄像头厂商提供的SDK
大华摄像头SDK
public class DahuaCamera {
public void play() {
System.out.println("Dahua Camera is playing.");
}
public void stop() {
System.out.println("Dahua Camera is stopping.");
}
public void fastForward() {
System.out.println("Dahua Camera is fast forwarding.");
}
public void viewHistory() {
System.out.println("Dahua Camera is viewing history.");
}
}
海康摄像头SDK
public class HikvisionCamera {
public void startPlay() {
System.out.println("Hikvision Camera is starting to play.");
}
public void stopPlay() {
System.out.println("Hikvision Camera is stopping.");
}
public void fastForwardPlay() {
System.out.println("Hikvision Camera is fast forwarding.");
}
public void viewHistoryPlay() {
System.out.println("Hikvision Camera is viewing history.");
}
}
3. 创建适配器类
海康摄像头适配器
public class HikvisionCameraAdapter implements CameraControl {
private HikvisionCamera hikvisionCamera;
public HikvisionCameraAdapter(HikvisionCamera hikvisionCamera) {
this.hikvisionCamera = hikvisionCamera;
}
public void play() {
hikvisionCamera.startPlay();
}
public void stop() {
hikvisionCamera.stopPlay();
}
public void fastForward() {
hikvisionCamera.fastForwardPlay();
}
public void viewHistory() {
hikvisionCamera.viewHistoryPlay();
}
}
大华适配器类似,从略。
4. 客户端代码
public class EmergencyResponseSystem {
public static void main(String[] args) {
CameraControl cameraControl = new HikvisionCameraAdapter(new HikvisionCamera());
cameraControl.play();
cameraControl.stop();
cameraControl.fastForward();
cameraControl.viewHistory();
}
}
5. 扩展性
通过使用适配器设计模式,我们可以将不同厂商的SDK适配到一个统一的接口下,使得应急指挥系统可以轻松地集成和替换不同厂商的监控摄像头,而不需要关心具体的实现细节。这样提高了系统的灵活性和可扩展性。
如果未来有新的厂商加入,我们只需要为新的厂商创建一个新的适配器类,而不需要修改现有的代码。例如,如果有一个名为“新视界”的厂商,我们只需要创建一个NewHorizonCameraAdapter
类,实现CameraControl
接口,并适配NewHorizonCamera
类的方法。
应用场景
日志框架SLF4J实际就是一个适配器模式的具体应用,注意虽然称之为日志门面,实际使用的实际模式并不是门面模式,而是适配器模式,通过定义统一的接口,通过实现具体的适配器,来集成具体的日志组件,如log4j2、logback等。
业务系统上传附件,可以选择多种存储模式,如服务器磁盘、MangoDB、私有MinIO对象存储、阿里云OSS存储等,同样可以基于适配器模式的思路,定义统一的功能接口,灵活切换存储模式。
同理,通知模式,采用短信、邮件、站内信、微信消息等,也可以采用类似的解决方案。
个人经验分享
- 全面了解:23种模式需要了解,首先得知道,在做系统设计的时候才会想到,有意识地使用。
- 借鉴思路:学习时不要死记硬背,场景驱动,侧重理解解决问题的设计思路,具体设计时,可以借鉴和参考思路,因此不一定完整运用设计模式,设计模式也有很多变种,甚至复杂问题需要组合使用的多种设计模式。
- 抓重点:23种设计模式,不需要平均分配时间精力,一方面,部分设计模式比较基础,如迭代器模式、享元模式,往往已封装在底层的jdk或中间件中了,通常直接使用,无需自行实现;另一方面,部分设计模式比较生僻,如抽象工厂、解释器,仅适用于特殊的场景,日常几乎不会使用到。对于这两类设计模式,需要了解应用场景和解决问题的实现思路即可。
- 重应用:企业应用开发,侧重于业务逻辑的实现,大多数功能用不上设计模式。但一些系统的复杂点、难点,如适合设计模式的应用场景,使用设计模式后会大幅提升系统的灵活性和扩展性。
- 经常复习:每隔2年左右,复习一遍,每次都有新的收获。
设计模式是技术人员的“内功”,需要持续“修炼”。
如果您在阅读本文时获得了帮助或受到了启发,希望您能够喜欢并收藏这篇文章,为它点赞~
请在评论区与我分享您的想法和心得,一起交流学习,不断进步,遇见更加优秀的自己!