当前位置: 首页 > 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数据库
  • css系列之关于字体的事
  • CSS中外联样式表代表的含义
  • Git的一些常用操作
  • Golang-长连接-状态推送
  • Invalidate和postInvalidate的区别
  • JDK 6和JDK 7中的substring()方法
  • Js基础——数据类型之Null和Undefined
  • spring-boot List转Page
  • Traffic-Sign Detection and Classification in the Wild 论文笔记
  • vue和cordova项目整合打包,并实现vue调用android的相机的demo
  • 闭包--闭包之tab栏切换(四)
  • 第三十一到第三十三天:我是精明的小卖家(一)
  • 基于游标的分页接口实现
  • 看图轻松理解数据结构与算法系列(基于数组的栈)
  • 如何学习JavaEE,项目又该如何做?
  • 深度学习入门:10门免费线上课程推荐
  • 使用 Node.js 的 nodemailer 模块发送邮件(支持 QQ、163 等、支持附件)
  • 使用阿里云发布分布式网站,开发时候应该注意什么?
  • 手机app有了短信验证码还有没必要有图片验证码?
  • 我的业余项目总结
  • 06-01 点餐小程序前台界面搭建
  • Java数据解析之JSON
  • ​ssh-keyscan命令--Linux命令应用大词典729个命令解读
  • ​二进制运算符:(与运算)、|(或运算)、~(取反运算)、^(异或运算)、位移运算符​
  • ​业务双活的数据切换思路设计(下)
  • #使用清华镜像源 安装/更新 指定版本tensorflow
  • (Redis使用系列) Springboot 使用Redis+Session实现Session共享 ,简单的单点登录 五
  • (二)fiber的基本认识
  • (简单) HDU 2612 Find a way,BFS。
  • (算法)Game
  • (转载)Linux 多线程条件变量同步
  • .NET 的程序集加载上下文
  • .net网站发布-允许更新此预编译站点
  • /*在DataTable中更新、删除数据*/
  • @KafkaListener注解详解(一)| 常用参数详解
  • @Service注解让spring找到你的Service bean
  • @我的前任是个极品 微博分析
  • [.NET]桃源网络硬盘 v7.4
  • [2010-8-30]
  • [ASP]青辰网络考试管理系统NES X3.5