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

.NET 设计模式—适配器模式(Adapter Pattern)

简介

适配器模式(Adapter Pattern):就是将一个类的接口转换成客户希望的另外一个接口。Adapter模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。

在计算机编程中,适配器模式(有时候也称包装样式或者包装)将一个类的接口适配成用户所期待的。一个适配允许通常因为接口不兼容而不能在一起工作的类工作在一起,做法是将类自己的接口包裹在一个已存在的类中。

适配器有类适配器和对象适配器两种类型,二者的意图相同,只是实现的方法和适用的情况不同。类适配器采用继承来实现,对象适配器则采用组合的方法来实现。

角色

  • 目标接口(Target):客户所期待的接口。目标可以是具体的或抽象的类,也可以是接口。
  • 需要适配的类(Adaptee):需要适配的类或适配者类。
  • 适配器(Adapter):通过包装一个需要适配的对象,把原接口转换成目标接口。  

优点

  • 通过适配器,客户端可以调用同一接口,因而对客户端来说是透明的。这样做更简单、更直接、更紧凑。
  • 复用了现存的类,解决了现存类和复用环境要求不一致的问题。
  • 将目标类和适配者类解耦,通过引入一个适配器类重用现有的适配者类,而无需修改原有代码。
  • 一个对象适配器可以把多个不同的适配者类适配到同一个目标,也就是说,同一个适配器可以把适配者类和它的子类都适配到目标接口。

缺点

  • 对于对象适配器来说,更换适配器的实现过程比较复杂。(可以用工厂模式解决)

应用场景

  • 系统需要使用现有的类,而此类的接口不符合系统的需要。
  • 想要建立一个可以重复使用的类,用于与一些彼此之间没有太大关联的一些类,包括一些可能在将来引进的类一起工作。这些源类不一定有很复杂的接口。
  • 仅对对象适配器而言,在设计里,需要改变多个已有子类的接口,如果使用类的适配器模式,就要针对每一个子类做一个适配器,而这不太实际。

案例

我们开发了一个项目,项目中采用了一个第三方的日志组件来记录日志,但是现在第三方日志组件实现的,现在我们自己开发了一个日志组件,我们想把项目中的日志组件替换为我们自己开发的,但是我们自己的开发的日志组件并没有实现第三方组件的接口,这个时候要怎么处理?

对象适配器实现(推荐)

  • 目标接口
/// <summary>
/// 目标接口
/// </summary>
public interface ILog
{/// <summary>/// 写日志的方法/// </summary>public void Write(string logCommand);
}
  • 需要适配的类
/// <summary>
/// 新开发的的日志接口类
/// </summary>
public abstract class ILogAbapter
{/// <summary>/// 新的写日志的方法/// </summary>/// <param name="logCommand"></param>public abstract void NewWrite(string logCommand);
}/// <summary>
/// 需要适配的数据库日志类
/// </summary>
public class DbLog : ILogAbapter
{public override void NewWrite(string logCommand){Console.WriteLine($"记录到数据库中:{logCommand}");}
}/// <summary>
/// 需要适配的文件日志类
/// </summary>
public class FileLog : ILogAbapter
{public override void NewWrite(string logCommand){Console.WriteLine($"记录到日志文件中:{logCommand}");}
}
  • 适配器
/// <summary>
/// 对象适配器
/// </summary>
public class LogAdapter : ILog
{private readonly ILogAbapter _logAdapter = null;public LogAdapter(ILogAbapter logAdapter){_logAdapter = logAdapter;}public void Write(string logCommand){_logAdapter.NewWrite(logCommand);}
}
  • 上层应用调用
{#region 对象适配器LogAdapter fileLog = new LogAdapter(new FileLogAdapter());fileLog.Write("hello word");LogAdapter dbLog = new LogAdapter(new DbLogAdapter());dbLog.Write("hello word");#endregion
}

类适配器实现

  • 目标接口
/// <summary>
/// 目标接口
/// </summary>
public interface ILog
{/// <summary>/// 写日志的方法/// </summary>public void Write(string logCommand);
}
  • 需要适配的类
/// <summary>
/// 新开发的的日志接口类
/// </summary>
public abstract class ILogAbapter
{/// <summary>/// 新的写日志的方法/// </summary>/// <param name="logCommand"></param>public abstract void NewWrite(string logCommand);
}/// <summary>
/// 需要适配的数据库日志类
/// </summary>
public class DbLog : ILogAbapter
{public override void NewWrite(string logCommand){Console.WriteLine($"记录到数据库中:{logCommand}");}
}/// <summary>
/// 需要适配的文件日志类
/// </summary>
public class FileLog : ILogAbapter
{public override void NewWrite(string logCommand){Console.WriteLine($"记录到日志文件中:{logCommand}");}
}
  • 适配器
/// <summary>
/// 数据库日志适配器
/// </summary>
public class DbLogAdapter : DbLog, ILog
{public void Write(string logCommand){NewWrite(logCommand);}
}/// <summary>/// 文件日志适配器/// </summary>public class FileLogAdapter : FileLog, ILog{public void Write(string logCommand){NewWrite(logCommand);}}
  • 上层应用调用
{#region 类适配器ILog fileLog = new FileLogAdapter();fileLog.Write("hello word");ILog dbLog = new DbLogAdapter();dbLog.Write("hello word");#endregion
}

总结

  • 对象适配用处是,可以使Adaptee不必实现不需要的方法,具体就是其表现形式就是父类实现缺省方法,而子类只需实现自己独特的方法。
  • 适配器类可以是抽象类。
  • 带参数的适配器模式。使用这种办法,适配器类可以根据参数返还一个合适的实例给客户端。

相关文章:

  • 《图解Vue3.0》- 调试
  • QT的安装
  • 【二分查找】Leetcode x 的平方根
  • OpenCV项目实战-深度学习去阴影-图像去阴影
  • Chatgpt掘金之旅—有爱AI商业实战篇|社交媒体管理|(七)
  • unity工程输出的log在哪里?
  • 手动实现Tomcat底层机制+自己设计Servlet
  • 倒三角形的两种输出方法
  • MES实施之工控机和电脑的选择
  • 条件变量的使用(golang)
  • 计算机网络-TCP重传、滑动窗口、流量控制、拥塞控制
  • 解决element-plus table组件 fixed=“right“(left)浮动后横向滚动文字穿透的问题
  • 【北邮国院大三下】Cybersecurity Law 网络安全法 Week1【更新Topic4, 5】_cyber security la
  • 12.自定义的多帧缓存架构
  • 【PostgreSQL】技术传承:使用Docker快速部署PostgreSQL数据库
  • [NodeJS] 关于Buffer
  • 【mysql】环境安装、服务启动、密码设置
  • 【附node操作实例】redis简明入门系列—字符串类型
  • create-react-app项目添加less配置
  •  D - 粉碎叛乱F - 其他起义
  • ES2017异步函数现已正式可用
  • ES6简单总结(搭配简单的讲解和小案例)
  • iOS仿今日头条、壁纸应用、筛选分类、三方微博、颜色填充等源码
  • Java到底能干嘛?
  • js算法-归并排序(merge_sort)
  • PHP 使用 Swoole - TaskWorker 实现异步操作 Mysql
  • ucore操作系统实验笔记 - 重新理解中断
  • 半理解系列--Promise的进化史
  • 观察者模式实现非直接耦合
  • 缓存与缓冲
  • 聊聊hikari连接池的leakDetectionThreshold
  • 巧用 TypeScript (一)
  • Salesforce和SAP Netweaver里数据库表的元数据设计
  • ​软考-高级-信息系统项目管理师教程 第四版【第19章-配置与变更管理-思维导图】​
  • #我与Java虚拟机的故事#连载17:我的Java技术水平有了一个本质的提升
  • (1)虚拟机的安装与使用,linux系统安装
  • (10)STL算法之搜索(二) 二分查找
  • (8)Linux使用C语言读取proc/stat等cpu使用数据
  • (强烈推荐)移动端音视频从零到上手(下)
  • (三)c52学习之旅-点亮LED灯
  • (最全解法)输入一个整数,输出该数二进制表示中1的个数。
  • .class文件转换.java_从一个class文件深入理解Java字节码结构
  • .NET Core实战项目之CMS 第一章 入门篇-开篇及总体规划
  • .NET Reactor简单使用教程
  • .NET Standard、.NET Framework 、.NET Core三者的关系与区别?
  • .NET 解决重复提交问题
  • .NET/C# 解压 Zip 文件时出现异常:System.IO.InvalidDataException: 找不到中央目录结尾记录。
  • .NET单元测试
  • @Autowired标签与 @Resource标签 的区别
  • @manytomany 保存后数据被删除_[Windows] 数据恢复软件RStudio v8.14.179675 便携特别版...
  • [1525]字符统计2 (哈希)SDUT
  • [Android] 240204批量生成联系人,短信,通话记录的APK
  • [caffe(二)]Python加载训练caffe模型并进行测试1
  • [Deep Learning] 神经网络基础
  • [dfs] 图案计数