当前位置: 首页 > news >正文

设计模式探索:适配器模式

1. 适配器模式介绍

1.1 适配器模式介绍

适配器模式(adapter pattern)的原始定义是:将一个类的接口转换为客户期望的另一个接口,适配器可以让不兼容的两个类一起协同工作。

适配器模式的主要作用是把原本不兼容的接口,通过适配修改做到统一,使得用户方便使用。比如,万能充电器和多接口数据线都是为了适配各种不同的接口。

在这里插入图片描述

为什么要转换接口?

  • 原接口和目标接口都已经存在,不易修改接口代码。
  • 抽象接口希望复用已有组件的逻辑。
1.2 适配器模式结构

适配器模式(Adapter)包含以下主要角色:

  • 目标(Target)接口:当前系统业务所期待的接口,它可以是抽象类或接口。
  • 适配者(Adaptee)类:被适配的角色,它是被访问和适配的现存组件库中的组件接口。
  • 适配器(Adapter)类:一个转换器,通过继承或引用适配者的对象,把适配者接口转换成目标接口,让客户按目标接口的格式访问适配者。

适配器模式分为:

  • 类适配器

    在这里插入图片描述

  • 对象适配器

    在这里插入图片描述

两者的区别在于:适配器与适配者的关系。类适配器是继承关系,对象适配器是聚合关系。根据设计原则,聚合优先于继承,应多选用对象适配器。

1.3 代码示例
// 目标接口
public interface Target {void request();
}// 适配者类
public class Adaptee {public void specificRequest() {System.out.println("适配者中的业务代码被调用!");}
}// 类适配器
public class ClassAdapter extends Adaptee implements Target {@Overridepublic void request() {this.specificRequest();}
}// 对象适配器
public class ObjectAdapter implements Target {private Adaptee adaptee;public ObjectAdapter(Adaptee adaptee) {this.adaptee = adaptee;}@Overridepublic void request() {this.adaptee.specificRequest();}
}// 测试代码
public class Client {public static void main(String[] args) {Target classAdapter = new ClassAdapter();classAdapter.request();Target objectAdapter = new ObjectAdapter(new Adaptee());objectAdapter.request();}
}

2. 适配器模式在实际开发中的应用

2.1 需求描述

为了提升系统的速度,将一些数据以 K-V 形式缓存在内存中,平台提供 get、put、remove 等 API 以及相关的管理机制。

功能实现的迭代过程,从 HashMap 到 Memcached 再到 Redis,要确保后面再增加新的缓存组件时,能够实现自由的切换,并且还要符合开闭原则。

在这里插入图片描述

设计问题:

  1. 如何在符合开闭原则前提下,实现功能的扩展?
  2. 两种客户端 API 不相同,如何保证自由切换?

使用适配器模式。

2.2 功能实现

使用适配器模式将功能相似的多种第三方组件(实现方案),统一成自己需要的 API,业务代码只依赖已经统一的 API,而不依赖第三方 API。

(1) 定义一个缓存接口,包含 get、put、remove 等操作方法。例如:

public interface Cache {void put(String key, Object value);Object get(String key);void remove(String key);
}

(2) 实现该接口的三个适配器,分别对应 HashMap、Memcached、Redis 三种缓存方案。例如:

// HashMap 适配器
public class HashMapCacheAdapter implements Cache {private Map<String, Object> cache = new HashMap<>();@Overridepublic void put(String key, Object value) {cache.put(key, value);}@Overridepublic Object get(String key) {return cache.get(key);}@Overridepublic void remove(String key) {cache.remove(key);}
}// Memcached 适配器
public class MemcachedCacheAdapter implements Cache {private MemcachedClient memcachedClient;public MemcachedCacheAdapter(MemcachedClient memcachedClient) {this.memcachedClient = memcachedClient;}@Overridepublic void put(String key, Object value) {memcachedClient.set(key, 0, value);}@Overridepublic Object get(String key) {return memcachedClient.get(key);}@Overridepublic void remove(String key) {memcachedClient.delete(key);}
}// Redis 适配器
public class RedisCacheAdapter implements Cache {private Jedis jedis;public RedisCacheAdapter(Jedis jedis) {this.jedis = jedis;}@Overridepublic void put(String key, Object value) {jedis.set(key, value.toString());}@Overridepublic Object get(String key) {return jedis.get(key);}@Overridepublic void remove(String key) {jedis.del(key);}
}

(3) 创建工厂类,根据配置文件中的配置来创建相应的缓存适配器。例如:

public class CacheAdapterFactory {public static Cache createCacheAdapter(String type) {if ("HashMap".equals(type)) {return new HashMapCacheAdapter();} else if ("Memcached".equals(type)) {MemCachedClient memCachedClient = new MemCachedClient();return new MemcachedCacheAdapter(memCachedClient);} else if ("Redis".equals(type)) {Jedis jedis = new Jedis("localhost", 6379);return new RedisCacheAdapter(jedis);} else {throw new IllegalArgumentException("Invalid cache type: " + type);}}
}

使用时,只需要调用工厂类的 createCacheAdapter 方法,传入缓存类型即可获取相应的缓存适配器。例如:

public class Client {public static void main(String[] args) {Cache cache = CacheAdapterFactory.createCacheAdapter("Redis");cache.put("key", "value");Object result = cache.get("key");cache.remove("key");}
}

3. 适配器模式总结

优点:

  1. 解耦合: 适配器模式允许两个没有直接关联的类协同工作,降低了它们之间的耦合度。
  2. 提高复用性: 通过适配器,可以重用现有的类,而不需要修改它们的代码。
  3. 统一接口: 适配器模式提供了一种方法来统一多个不同的接口,使得它们可以被统一对待。
  4. 隐藏实现: 适配器模式隐藏了现有类的实现细节,只暴露出需要的接口。
  5. 灵活性: 可以根据需要自由地适配不同的类,提供了高度的灵活性。

缺点:

  1. 单一适配限制: 使用类适配器时,一次最多只能适配一个适配者类,这可能限制了其应用范围。
  2. 系统复杂度: 如果过度使用适配器,可能会导致系统结构变得复杂,难以理解和维护。

适用场景:

  1. 接口统一: 当需要统一多个类的接口时,适配器模式可以有效地将它们适配到一个统一的接口。
  2. 兼容性需求: 当现有的接口无法修改,但需要与其他系统或模块兼容时,适配器模式可以提供解决方案。

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 关于ppmlhdfe和possion两个命令回归显示观测值不同
  • 掌握计算机网络基础:从零开始的指南
  • 基于conda包的环境创建、激活、管理与删除
  • 鸿蒙语言基础类库:【@ohos.util.HashMap (非线性容器HashMap)】
  • mes系统在新材料行业中的应用价值
  • 谷粒商城-个人笔记(集群部署篇三)
  • 定义变量和声明变量、定义类和声明类
  • 哈喽GPT-4o,程序员如何通过GPT-4o提高办公效率
  • Score matching
  • [终端安全]-7 后量子密码算法
  • 力扣-排序算法
  • uniapp js 用dom创建form表单 并提交
  • 【机器学习】主成分分析(PCA):数据降维的艺术
  • C语言 | Leetcode C语言题解之第226题翻转二叉树
  • DP学习——观察者模式
  • Angular数据绑定机制
  • DOM的那些事
  • iOS 系统授权开发
  • Linux CTF 逆向入门
  • 从@property说起(二)当我们写下@property (nonatomic, weak) id obj时,我们究竟写了什么...
  • 得到一个数组中任意X个元素的所有组合 即C(n,m)
  • 官方解决所有 npm 全局安装权限问题
  • 每天10道Java面试题,跟我走,offer有!
  • 首页查询功能的一次实现过程
  • 通过几道题目学习二叉搜索树
  • 微信开源mars源码分析1—上层samples分析
  • 小而合理的前端理论:rscss和rsjs
  • 走向全栈之MongoDB的使用
  • ​无人机石油管道巡检方案新亮点:灵活准确又高效
  • !!【OpenCV学习】计算两幅图像的重叠区域
  • #stm32驱动外设模块总结w5500模块
  • #我与Java虚拟机的故事#连载12:一本书带我深入Java领域
  • (C语言版)链表(三)——实现双向链表创建、删除、插入、释放内存等简单操作...
  • (zt)最盛行的警世狂言(爆笑)
  • (安全基本功)磁盘MBR,分区表,活动分区,引导扇区。。。详解与区别
  • (学习日记)2024.01.09
  • (一)Spring Cloud 直击微服务作用、架构应用、hystrix降级
  • (原創) 如何將struct塞進vector? (C/C++) (STL)
  • ./configure,make,make install的作用(转)
  • .NET 5.0正式发布,有什么功能特性(翻译)
  • .NET Framework杂记
  • .net oracle 连接超时_Mysql连接数据库异常汇总【必收藏】
  • .net redis定时_一场由fork引发的超时,让我们重新探讨了Redis的抖动问题
  • .NET 依赖注入和配置系统
  • .NET 中的轻量级线程安全
  • .NET/C# 编译期间能确定的相同字符串,在运行期间是相同的实例
  • .net操作Excel出错解决
  • .Net多线程Threading相关详解
  • .NET框架类在ASP.NET中的使用(2) ——QA
  • @Bean, @Component, @Configuration简析
  • @RequestBody的使用
  • [.net 面向对象程序设计进阶] (19) 异步(Asynchronous) 使用异步创建快速响应和可伸缩性的应用程序...
  • [1204 寻找子串位置] 解题报告
  • [2008][note]腔内级联拉曼发射的,二极管泵浦多频调Q laser——
  • [AI Google] Ask Photos: 使用Gemini搜索照片的新方法