设计模式探索:适配器模式
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,要确保后面再增加新的缓存组件时,能够实现自由的切换,并且还要符合开闭原则。
设计问题:
- 如何在符合开闭原则前提下,实现功能的扩展?
- 两种客户端 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. 适配器模式介绍 1.1 适配器模式介绍 适配器模式(adapter pattern)的原始定义是:将一个类的接口转换为客户期望的另一个接口,适配器可以让不兼容的两个类一起协同工作。 适配器模式的主要作用是把原本不兼容的接口,…...

OpenCV 寻找棋盘格角点及绘制
目录 一、概念 二、代码 2.1实现步骤 2.2完整代码 三、实现效果 一、概念 寻找棋盘格角点(Checkerboard Corners)是计算机视觉中相机标定(Camera Calibration)过程的重要步骤。 OpenCV 提供了函数 cv2.findChessboardCorners…...

【深度学习】PyTorch深度学习笔记02-线性模型
1. 监督学习 2. 数据集的划分 3. 平均平方误差MSE 4. 线性模型Linear Model - y x * w 用穷举法确定线性模型的参数 import numpy as np import matplotlib.pyplot as pltx_data [1.0, 2.0, 3.0] y_data [2.0, 4.0, 6.0]def forward(x):return x * wdef loss(x, y):y_pred…...

10.FreeRTOS_互斥量
互斥量概述 在博文“ FreeRTOS_信号量 ”中,使用了二进制信号量实现了互斥,保护了串口资源。博文链接如下: FreeRTOS_信号量-CSDN博客 但还是要引入互斥量的概念。互斥量与二进制信号量相比,能够多实现如下两个功能:…...

EtherCAT总线冗余让制造更安全更可靠更智能
冗余定义 什么是总线冗余功能?我们都知道,EtherCAT现场总线具有灵活的拓扑结构,设备间支持线型、星型、树型的连接方式,其中线型结构简单、传输效率高,大多数的现场应用中也是使用这种连接方式,如下图所示…...
Android IdleHandler源码分析
文章目录 Android IdleHandler源码分析概述前提基本用法源码分析添加和删除任务执行任务 应用场景 Android IdleHandler源码分析 概述 IdleHandler是一个接口,它定义在MessageQueue类中,用于在主线程的消息队列空闲时执行一些轻量级的任务。IdleHandle…...

Mac安装stable diffusion 工具
文章目录 1.安装 Homebrew2.安装 stable diffusion webui 的依赖3.下载 stable diffusion webui 代码4.启动 stable diffusion webui 本体5.下载模型6.这里可能会遇到一个clip-vit-large-patch14报错 参考:https://brew.idayer.com/install/stable-diffusion-webui/…...

CVE-2024-6387Open SSH漏洞彻底解决举措(含踩坑内容)
一、漏洞名称 OpenSSH 远程代码执行漏洞(CVE-2024-6387) 二、漏洞概述 Open SSH是基于SSH协议的安全网络通信工具,广泛应用于远程服务器管理、加密文件传输、端口转发、远程控制等多个领域。近日被爆出存在一个远程代码执行漏洞,由于Open SSH服务器端…...

python的简单爬取
需要的第三方模块 requests winr打开命令行输入cmd 简单爬取的基本格式(爬取百度logo为例) import requests url"http://www.baidu.com/img/PCtm_d9c8750bed0b3c7d089fa7d55720d6cf.png" resprequests.get(url)#回应 #保存到本地 with open(&…...

【WEB前端2024】3D智体编程:乔布斯3D纪念馆-第60集-agent训练资讯APP重点推荐AI资讯内容(含视频)
【WEB前端2024】3D智体编程:乔布斯3D纪念馆-第60集-agent训练资讯APP重点推荐AI资讯内容(含视频) 使用dtns.network德塔世界(开源的智体世界引擎),策划和设计《乔布斯超大型的开源3D纪念馆》的系列教程。d…...

【学术会议征稿】第三届智能电网与能源系统国际学术会议
第三届智能电网与能源系统国际学术会议 2024 3rd International Conference on Smart Grid and Energy Systems 第三届智能电网与能源系统国际学术会议(SGES 2024)将于2024年10月25日-27日在郑州召开。 智能电网可以优化能源布局,让现有能源…...

01. 课程简介
1. 课程简介 本课程的核心内容可以分为三个部分,分别是需要理解记忆的计算机底层基础,后端通用组件以及需要不断编码练习的数据结构和算法。 计算机底层基础可以包含计算机网络、操作系统、编译原理、计算机组成原理,后两者在面试中出现的频…...
iOS热门面试题(三)
面试题1:在iOS开发中,什么是MVC设计模式?请详细解释其各个组成部分,并给出一个实际应用场景,包括具体的代码实现。 答案: MVC设计模式是一种在软件开发中广泛使用的架构模式,特别是在iOS开发中…...
ECS中postTransform.Value = float4x4.Scale(1, math.sin(elapsedTime), 1)
在Unity的ECS(Entity Component System)架构中,postTransform.Value float4x4.Scale(1, math.sin(elapsedTime), 1); 用于设置一个变换矩阵的缩放部分。下面是对这行代码的详细解释: postTransform: 这是一个表示变换的组件或结构…...

VLM技术介绍
1、背景 视觉语言模型(Visual Language Models)是可以同时从图像和文本中学习以处理许多任务的模型,从视觉问答到图像字幕。 视觉识别(如图像分类、物体保护和语义分割)是计算机视觉研究中一个长期存在的难题ÿ…...

x264 编码器 AArch64 汇编函数模块关系分析
x264 编码器 AArch64 汇编介绍 x264 是一个流行的开源视频编码器,它实现了 H.264/MPEG-4 AVC 标准。x264 项目致力于提供一个高性能、高质量的编码器,支持多种平台和架构。对于 AArch64(即 64 位 ARM 架构),x264 编码器利用该架构的特性来优化编码过程。在 x264 编码器中,…...

windows10开启防火墙,增加入站规则后不生效,还是不能访问后端程序
一、背景: 公司护网要求开启防火墙,开启防火墙后,前后端分离的项目调试受影响,于是增加入站规则开放固定的后台服务端口,增加的mysql端口3306和redis端口6379,别人都可以访问,但是程序的端口808…...

academic-homepage:快速搭建个人学术主页,页面内容包括个人简介、教育经历、发布过的学术列表等,同时页面布局兼容移动端。
今天给大家分享GitHub 上一个开源的 GitHub Pages 模板 academic-homepage。 可帮助你快速搭建个人学术主页,页面内容包括个人简介、教育经历、发布过的学术列表等最基本内容,同时页面布局兼容移动端。 相关链接 github.com/luost26/academic-homepage …...
.env.development、.env.production、.env.staging
环境变量文件(如 .env.development、.env.production、.env.staging)用于根据不同的环境(开发、生产、测试等)配置应用程序的行为。 作用 .env.development:用于开发环境的配置。开发人员在本地开发时会使用这个文件…...
国密证书(gmssl)在Kylin Server V10下安装
1.查看操作系统信息 [root@localhost ~]# cat /etc/.kyinfo [dist] name=Kylin milestone=Server-V10-GFB-Release-ZF9_01-2204-Build03 arch=arm64 beta=False time=2023-01-09 11:04:36 dist_id=Kylin-Server-V10-GFB-Release-ZF9_01-2204-Build03-arm64-2023-01-09 11:04:…...
java调用dll出现unsatisfiedLinkError以及JNA和JNI的区别
UnsatisfiedLinkError 在对接硬件设备中,我们会遇到使用 java 调用 dll文件 的情况,此时大概率出现UnsatisfiedLinkError链接错误,原因可能有如下几种 类名错误包名错误方法名参数错误使用 JNI 协议调用,结果 dll 未实现 JNI 协…...

CentOS下的分布式内存计算Spark环境部署
一、Spark 核心架构与应用场景 1.1 分布式计算引擎的核心优势 Spark 是基于内存的分布式计算框架,相比 MapReduce 具有以下核心优势: 内存计算:数据可常驻内存,迭代计算性能提升 10-100 倍(文档段落:3-79…...

初学 pytest 记录
安装 pip install pytest用例可以是函数也可以是类中的方法 def test_func():print()class TestAdd: # def __init__(self): 在 pytest 中不可以使用__init__方法 # self.cc 12345 pytest.mark.api def test_str(self):res add(1, 2)assert res 12def test_int(self):r…...

安宝特案例丨Vuzix AR智能眼镜集成专业软件,助力卢森堡医院药房转型,赢得辉瑞创新奖
在Vuzix M400 AR智能眼镜的助力下,卢森堡罗伯特舒曼医院(the Robert Schuman Hospitals, HRS)凭借在无菌制剂生产流程中引入增强现实技术(AR)创新项目,荣获了2024年6月7日由卢森堡医院药剂师协会࿰…...

逻辑回归暴力训练预测金融欺诈
简述 「使用逻辑回归暴力预测金融欺诈,并不断增加特征维度持续测试」的做法,体现了一种逐步建模与迭代验证的实验思路,在金融欺诈检测中非常有价值,本文作为一篇回顾性记录了早年间公司给某行做反欺诈预测用到的技术和思路。百度…...

mac:大模型系列测试
0 MAC 前几天经过学生优惠以及国补17K入手了mac studio,然后这两天亲自测试其模型行运用能力如何,是否支持微调、推理速度等能力。下面进入正文。 1 mac 与 unsloth 按照下面的进行安装以及测试,是可以跑通文章里面的代码。训练速度也是很快的。 注意…...

针对药品仓库的效期管理问题,如何利用WMS系统“破局”
案例: 某医药分销企业,主要经营各类药品的批发与零售。由于药品的特殊性,效期管理至关重要,但该企业一直面临效期问题的困扰。在未使用WMS系统之前,其药品入库、存储、出库等环节的效期管理主要依赖人工记录与检查。库…...
怎么开发一个网络协议模块(C语言框架)之(六) ——通用对象池总结(核心)
+---------------------------+ | operEntryTbl[] | ← 操作对象池 (对象数组) +---------------------------+ | 0 | 1 | 2 | ... | N-1 | +---------------------------+↓ 初始化时全部加入 +------------------------+ +-------------------------+ | …...

VSCode 使用CMake 构建 Qt 5 窗口程序
首先,目录结构如下图: 运行效果: cmake -B build cmake --build build 运行: windeployqt.exe F:\testQt5\build\Debug\app.exe main.cpp #include "mainwindow.h"#include <QAppli...

新版NANO下载烧录过程
一、序言 搭建 Jetson 系列产品烧录系统的环境需要在电脑主机上安装 Ubuntu 系统。此处使用 18.04 LTS。 二、环境搭建 1、安装库 $ sudo apt-get install qemu-user-static$ sudo apt-get install python 搭建环境的过程需要这个应用库来将某些 NVIDIA 软件组件安装到 Je…...