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

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. 兼容性需求: 当现有的接口无法修改,但需要与其他系统或模块兼容时,适配器模式可以提供解决方案。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/376390.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

提高使用安全,智慧校园在线用户功能概述

智慧校园系统融入了一个查看当前在线用户的功能&#xff0c;这一设计旨在为管理人员提供一个实时的窗口&#xff0c;洞悉校园平台的即时活跃情况&#xff0c;确保系统的高效运作与环境安全。通过这一功能&#xff0c;管理员能够一目了然地看到所有正活跃在平台上的用户群体&…

server nat表和会话表的作用及NAT地址转换详细

本章节主要讲nat技术的基础 -会话表的建立也是看5元组 -状态检测技术的回包一样也看5元组&#xff0c;但是状态检测技术会看的除开5元组还有更多东西 老哥&#xff0c;你真的应该好好注意一个东西&#xff1a;我们的会话表只是为了后续包的转发&#xff0c;会话表是记录的首…

视频播放器的问题

<template><div class"app-container"><el-form :model"queryParam" ref"queryForm" :inline"true"><el-form-item label"题目ID&#xff1a;"><el-input v-model"queryParam.id" cle…

WEB07Vue+Ajax

1. Vue概述 Vue&#xff08;读音 /vjuː/, 类似于 view&#xff09;&#xff0c;是一款用于构建用户界面的渐进式的JavaScript框架&#xff08;官方网站&#xff1a;https://cn.vuejs.org&#xff09;。 在上面的这句话中呢&#xff0c;出现了三个词&#xff0c;分别是&#x…

在Linux系统实现瑞芯微RK3588部署rknntoolkit2进行模型转换

一、首先要先安装一个虚拟的环境 安装Miniconda包 Miniconda的官网链接:Minidonda官网 下载好放在要操作的linux系统,我用的是远程服务器的linux系统,我放在whl这个文件夹里面,这个文件夹是我自己创建的 运行安装 安装的操作都是yes就可以了 检查是否安装成功,输入下面…

Qt开发 | Qt绘图技术 | 常见图像绘制 | Qt移动鼠标绘制任意形状 | Qt绘制带三角形箭头的窗口

文章目录 一、基本绘图技术介绍二、常见的18种图形、路径、文字、图片绘制三、Qt移动鼠标绘制任意形状四、Qt绘制带三角形箭头的窗口 一、基本绘图技术介绍 Qt提供了绘图技术&#xff0c;程序员可以在界面上拖动鼠标&#xff0c;或者在代码里指定参数进行绘图。 Qt绘图技术介绍…

系统架构师考点--软件工程(上)

大家好。今天我来总结一下软件工程的相关考点。这部分是考试的重点。在上午场客观题、下午场案例题以及下午场论文都有可能考到&#xff0c;在上午场客观题中大约占12-15分左右。 一、软件工程概述 软件开发生命周期 软件定义时期&#xff1a;包括可行性研究和详细需求分析过…

单元测试实施最佳方案(背景、实施、覆盖率统计)

1. 什么是单元测试&#xff1f; 对于很多开发人员来说&#xff0c;单元测试一定不陌生 单元测试是白盒测试的一种形式&#xff0c;它的目标是测试软件的最小单元——函数、方法或类。单元测试的主要目的是验证代码的正确性&#xff0c;以确保每个单元按照预期执行。单元测试通…

构建高精度室内定位导航系统,从3DGIS到AI路径规划的全面解析

室内定位导航系统是一种利用多种技术实现室内精准定位和导航的智能系统&#xff0c;即便没有卫星信号&#xff0c;也能实现精准导航。维小帮室内定位导航系统是基于自研的地图引擎与先进定位技术&#xff0c;结合智能路径规划算法&#xff0c;解决了人们在大型复杂室内场所最后…

【Linux】多线程_3

文章目录 九、多线程3. C11中的多线程4. 线程的简单封装 未完待续 九、多线程 3. C11中的多线程 Linux中是根据多线程库来实现多线程的&#xff0c;C11也有自己的多线程&#xff0c;那它的多线程又是怎样的&#xff1f;我们来使用一些C11的多线程。 Makefile&#xff1a; te…

Unity基础调色

叭叭叭 最近&#xff08;*这两天&#xff09;因为想做一些Unity的调色问题&#xff0c;尝试原文翻译一下&#xff0c;其实直接原文更好&#xff01;&#xff01; Color Grading 参考了&#xff0c;某大牛的翻译&#xff0c;实在忍不住了&#xff0c;我是不知道为什么能翻译成…

Vivado 2020.1 HLS IP在BD模式无法生成问题

折腾了一周整整&#xff0c;记录一下&#xff0c;希望对大家有用。 各种找、各种操作&#xff0c;也问了FAE&#xff0c;都没搞定。 最后看到如下博文的方法3&#xff0c;管用。 vivado综合hls类ip核报错问题解决方案_vivado ip synth checkpoint mode-CSDN博客 报错描述 m…

论文翻译:Large Language Models for Education: A Survey and Outlook

https://arxiv.org/abs/2403.18105 目录 教育领域的大型语言模型&#xff1a;一项调查和展望摘要1. 引言2. 教育应用中的LLM2.1 概述2.2 学习辅助2.2.1 问题解决&#xff08;QS&#xff09; 2.2.2 错误纠正&#xff08;EC&#xff09;2.2.3 困惑助手&#xff08;CH&#xff09;…

Jenkins中Node节点与构建任务

目录 节点在 Jenkins 中的主要作用 1. 分布式构建 分布式处理 负载均衡 2. 提供不同的运行环境 多平台支持 特殊环境需求 3. 提高资源利用率 动态资源管理 云端集成 4. 提供隔离和安全性 任务隔离 权限控制 5. 提高可扩展性 横向扩展 高可用性 Jenkins 主服务…

【香菇带你学Linux】Linux环境下gcc编译安装【建议收藏】

文章目录 0. 前言1. 安装前准备工作1.1 创建weihu用户1.2 安装依赖包1.2.1 安装 GMP1.2.2 安装MPFR1.2.3 安装MPC 2. gcc10.0.1版本安装3. 报错解决3. 1. wget下载报错 4. 参考文档 0. 前言 gcc&#xff08;GNU Compiler Collection&#xff09;是GNU项目的一部分&#xff0c;…

excel 百分位函数 学习

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、函数说明PERCENTILE 函数PERCENTILE.inc 函数PERCENTILE.exc 函数QUARTILE.EXC 函数 二、使用步骤总结 前言 excel 百分位函数 Excel提供了几个函数用于…

ctfshow-web入门-php特性(web100-web103)is_numeric 函数绕过

目录 1、web100 2、web101 3、web102 4、web103 1、web100 提示&#xff1a;flag in class ctfshow&#xff0c;我们只需要构造输出 ctfshow 这个类即可。 代码分析&#xff1a; $v0is_numeric($v1) and is_numeric($v2) and is_numeric($v3); if($v0){ 虽然逻辑运算符的…

Spring Boot整合Druid:轻松实现SQL监控和数据库密码加密

文章目录 1 引言1.1 简介1.2 Druid的功能1.3 竞品对比 2 准备工作2.1 项目环境 3 集成Druid3.1 添加依赖3.2 配置Druid3.3 编写测试类测试3.4 访问控制台3.5 测试SQL监控3.6 数据库密码加密3.6.1 执行命令加密数据库密码3.6.2 配置参数3.6.3 测试 4 总结 1 引言 1.1 简介 Dru…

gfast前端UI:基于Vue3与vue-next-admin适配手机、平板、pc 的后台开源模板

摘要 随着现代软件开发的高效化需求&#xff0c;一个能够快速适应不同设备、简化开发过程的前端模板变得至关重要。gfast前端UI&#xff0c;基于Vue3.x和vue-next-admin&#xff0c;致力于提供这样一个解决方案。本文将深入探讨gfast前端UI的技术栈、设计原则以及它如何适配手机…

Neo4j:图数据库的革命性力量

Neo4j 首席技术官 prathle 撰写了一篇出色的博文&#xff0c;总结最近围绕 GraphRAG 的热议、我们从一年来帮助用户使用知识图谱 LLM 构建系统中学到的东西&#xff0c;以及我们认为该领域的发展方向。Neo4j一时间又大火起来&#xff0c;本文将带你快速入门这神奇的数据库。 前…