〇、简介

1、什么是适配器模式?

一句话解释:

  两个无关联的类,通过实现同一接口或继承对方得到新的适配器类,新的适配器类中通过实现原本类的操作,可达到进行相同的操作的目的。

适配器模式(Apapter Pattern)是一种结构型设计模式,用于将一个类的实现转换成客户端所期望的另一个类,这个类中的操作和目标类具有相同的操作,以达到两个不相关的类可以互操作的目的。

官方意图:将一个类的接口转换成客户希望的另外一个接口。使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。

 一个比喻:(两位来自不同方言区的学生)

  分别来自广州和海口的两位同学,如果都各自说自己的家乡话粤语和海南话,则根本无法沟通,此时普通话就是一个适配器,将两种方言翻译成普通话来进行适配,这样就可以顺畅沟通了。

2、优缺点和使用场景

优缺点:

  • 通过适配器模式,可以使两个不兼容的接口协同工作,避免了修改现有代码的需要。
  • 提高了代码的复用性和灵活性,因为适配器可以重复使用,并且可以在不同的场景中使用。
  • 降低了系统的耦合度,适配器模式允许系统中的各个组件相互独立地演化。
  • 由于引入了适配器类,可能造成系统的复杂度增加。
  • 在某些情况下,可能需要创建多个适配器来满足不同的客户端需求。

适用场景:

  • 当需要使用一个已经存在的类,但其接口与你的需求不兼容时,可以使用适配器模式。
  • 当想要创建一个可复用的类,该类与一些不相关或不可预见的类进行交互时,适配器模式也是很有用的。
  • 当希望通过一个统一的接口与多个类进行交互时,适配器模式可以提供一个统一的接口。
  • 当需要在不破坏现有代码结构的情况下,对已有的类进行功能扩展时,可以考虑使用适配器模式。

实际使用场景举例:

  • 旧系统与新系统的兼容:当需要将一个旧系统的接口适配成一个新系统可以使用的接口时,适配器模式非常有用。通过创建一个适配器类,可以使新系统能够无缝地与老旧系统进行通信,而不需要修改新系统的代码。
  • 第三方组件的集成:当我们需要使用某个第三方组件,但其提供的接口与我们的系统需求不一致时,可以使用适配器模式。适配器可以将第三方组件的接口转换为符合我们系统需求的接口形式,从而能够顺利地集成到我们的系统中。
  • 多个类库之间的互操作:当我们需要在多个类库之间进行互操作,但它们之间的接口不兼容时,适配器模式可以起到桥梁的作用。通过创建适配器类,将不同类库的接口转换为统一的接口,实现它们之间的互操作性。
  • 接口的标准化:当系统中存在多个类似但接口不同的组件时,可以使用适配器模式将它们的接口标准化。通过适配器,这些组件可以统一使用相同的接口,从而提高系统的一致性和可维护性。
  • 对已有类的功能扩展:当我们需要对一个已有的类进行功能扩展时,可以使用适配器模式。通过创建适配器类,将新功能与原有类进行适配,使得原有类能够使用新功能,同时不影响原有代码的稳定性。

一、通过示例简单实现

下面是一个使用适配器设计模式的示例,假设我们有一个电源插座接口 ISocket,其中定义了供电方法 SupplyPower():

class Program // 测试
{
static void Main(string[] args)
{
// 国标插座
ChinaSocket chinaSocket = new ChinaSocket();
ChinaSocketAdapter chinaAdapter = new ChinaSocketAdapter(chinaSocket);
Laptop laptop1 = new Laptop(chinaAdapter); // 笔记本1 通过国标版插座充电
laptop1.Charge();
// 美版插座
USASocket usaSocket = new USASocket();
USASocketAdapter usaAdapter = new USASocketAdapter(usaSocket);
Laptop laptop2 = new Laptop(usaAdapter); // 同一类型的笔记本2 通过美标版插座充电
laptop2.Charge();
Console.ReadKey();
}
}
// 电源插座接口
public interface ISocket
{
void SupplyPower();
}
// 国标版插口
public class ChinaSocket
{
public string name { get; set; }
public void Charge()
{
Console.WriteLine("开始充电!");
}
}
// 美版插口
public class USASocket
{
public string name { get; set; }
public void PowerUp()
{
Console.WriteLine("Start charging!");
}
}
// 国标版的适配器,实现统一的电源插座接口
public class ChinaSocketAdapter : ISocket
{
private readonly ChinaSocket _chinaSocket;
public ChinaSocketAdapter(ChinaSocket chinaSocket)
{
_chinaSocket = chinaSocket;
}
public void SupplyPower() // 国标版实现充电方法,调用特有的 Charge() 方法
{
_chinaSocket.Charge();
}
}
// 美版插座适配器,实现统一的插座接口
public class USASocketAdapter : ISocket
{
private readonly USASocket _usaSocket;
public USASocketAdapter(USASocket usaSocket)
{
_usaSocket = usaSocket;
}
public void SupplyPower() // 美版实现充电方法,调用特有的 PowerUp() 方法
{
_usaSocket.PowerUp();
}
}
// 笔记本电脑类实现,统一充电方法 Charge()
public class Laptop
{
private readonly ISocket _socket;
public Laptop(ISocket socket)
{
_socket = socket;
}
public void Charge()
{
_socket.SupplyPower();
}
}

最终,无论是国标还是美版的插座,均调用 Charge() 方法进行充电,充当适配器角色的就是电源插座接口 IScoket。

二、适配器模式的结构

如下简单画一下上一章节示例代码对应的类图:(美版相似就省略了,只显示国标版)

Client:给 Laptop 声明插座并完成充电动作。

Laptop:定义统一充电接口的模板,供适配器实现。

ChinaSocketAdapter:对 ChinaSocket 类和 Laptop 进行适配。

ChinaSocket:已存在的类,此类需要适配。

三、适配器模式在 .Net Core 中的实际应用

IDataAdapter 接口的实现类通常是数据库访问器,它们提供了一种与特定数据库类型无关的方式来访问数据。

下面是接口 IDataAdapter 的源码:

// System.Data.Common, Version=7.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
// System.Data.IDataAdapter
using System.Data;
using System.Diagnostics.CodeAnalysis; public interface IDataAdapter
{
MissingMappingAction MissingMappingAction { get; set; } MissingSchemaAction MissingSchemaAction { get; set; } ITableMappingCollection TableMappings { get; } [RequiresUnreferencedCode("IDataReader's (built from adapter commands) schema table types cannot be statically analyzed.")]
DataTable[] FillSchema(DataSet dataSet, SchemaType schemaType); int Fill(DataSet dataSet); IDataParameter[] GetFillParameters(); [RequiresUnreferencedCode("IDataReader's (built from adapter commands) schema table types cannot be statically analyzed.")]
int Update(DataSet dataSet);
}

具体的数据库,均实现了 IDataAdapter 接口:

// SQL Server
public sealed class SqlDataAdapter : DbDataAdapter, IDataAdapter, IDbDataAdapter, ICloneable
{ ... }
// Oracle
[Designer("Oracle.VsDevTools.OracleVSGDataAdapterWizard, Oracle.VsDevTools, Version=4.122.1.0, Culture=neutral, PublicKeyToken=89b483f429c47342, processorArchitecture=MSIL", typeof(IDesigner))]
[ToolboxBitmap(typeof(resfinder), "Oracle.ManagedDataAccess.src.Client.Icons.OracleDataAdapterToolBox_hc.bmp")]
[DefaultEvent("RowUpdated")]
public sealed class OracleDataAdapter : DbDataAdapter, IDbDataAdapter, IDataAdapter
{ ... }
// MySQL
[DesignerCategory("Code")]
[Designer("MySql.Data.MySqlClient.Design.MySqlDataAdapterDesigner,MySqlClient.Design")]
public sealed class MySqlDataAdapter : DbDataAdapter, IDbDataAdapter, IDataAdapter
{ ... }

通过使用 IDataAdapter 接口,我们可以编写与特定数据库类型无关的代码,而只需要关心数据集的结构和操作。这样,我们就可以更轻松地更换或扩展我们的数据源,而不需要修改应用程序的代码。同时,IDataAdapter 接口还支持数据映射和数据验证等高级功能,使得我们可以更好地处理复杂的数据操作。

四、相关模式

桥接模式(Bridge)的结构与对象适配器类似,但是 Bridge 模式的出发点不同。Bridge 的目的是将接口部分和实现部分分离,从而可以对它们较为容易也相对独立地加以改变。而 Adapter  则意味着改变一个已有对象的接口。

装饰模式(Decorator)增强了其他对象的功能而同时又不改变它的接口,因此 Decorator 对应用程序的透明性比适配器要好。结果是 Decorator 支持递归组合,而纯粹使用适配器是不可能实现这一点的。

代理模式(Proxy)在不改变它的接口的条件下,为另一个对象定义了一个代理。

Adapter 适配器模式简介与 C# 示例【结构型1】【设计模式来了_6】的更多相关文章

  1. C#设计模式之七适配器模式(Adapter)【结构型】

    一.引言   从今天开始我们开始讲[结构型]设计模式,[结构型]设计模式有如下几种:适配器模式.桥接模式.装饰模式.组合模式.外观模式.享元模式.代理模式.[创建型]的设计模式解决的是对象创建的问题, ...

  2. C#设计模式之六适配器模式(Adapter Pattern)【结构型】

    一.引言 从今天开始我们开始讲[结构型]设计模式,[结构型]设计模式有如下几种:适配器模式.桥接模式.装饰模式.组合模式.外观模式.享元模式.代理模式.[创建型]的设计模式解决的是对象创建的问题,那[ ...

  3. C++ 设计模式 3:结构型模式

    0 结构型模式 让类和类进行组合,获得更大的结构,获得新功能的方式. 1 代理模式 Proxy 模式又被叫做代理模式,是结构型的设计模式之一,它可以 为其他对象提供一种代理以控制对这个对象的访问. 所 ...

  4. (Java)设计模式:结构型

    前言 这篇博文续接的是 UML建模.设计原则.创建型设计模式.行为型设计模式,有兴趣的可以看一下 3.3.结构型 这些设计模式关注类和对象的组合.将类和对象组合在一起,从而形成更大的结构 * 3.3. ...

  5. 面向对象程序设计(OOP设计模式)-结构型模式之装饰器模式的应用与实现

    课程名称:程序设计方法学 实验4:OOP设计模式-结构型模式的应用与实现 时间:2015年11月18日星期三,第3.4节 地点:理1#208 一.实验目的 加深对结构型设计模式的理解以及在开发中的实际 ...

  6. Go语言实现的23种设计模式之结构型模式

    摘要:本文主要聚焦在结构型模式(Structural Pattern)上,其主要思想是将多个对象组装成较大的结构,并同时保持结构的灵活和高效,从程序的结构上解决模块之间的耦合问题. 本文分享自华为云社 ...

  7. C#设计模式之十一外观模式(Facade)【结构型】

    一.引言 快12点半了,要开始今天的写作了.很快,转眼设计模式已经写了十个了,今天我们要讲[结构型]设计模式的第五个模式,该模式是[外观模式],英文名称是:Facade Pattern.我们先从名字上 ...

  8. C#设计模式之十三代理模式(Proxy)【结构型】

    一.引言   今天我们要讲[结构型]设计模式的第七个模式,也是"结构型"设计模式中的最后一个模式,该模式是[代理模式],英文名称是:Proxy Pattern.还是老套路,先从名字 ...

  9. C#设计模式之十外观模式(Facade Pattern)【结构型】

    一.引言 快12点半了,要开始今天的写作了.很快,转眼设计模式已经写了十个了,今天我们要讲[结构型]设计模式的第五个模式,该模式是[外观模式],英文名称是:Facade Pattern.我们先从名字上 ...

  10. C#设计模式之十二代理模式(Proxy Pattern)【结构型】

    一.引言 今天我们要讲[结构型]设计模式的第七个模式,也是“结构型”设计模式中的最后一个模式,该模式是[代理模式],英文名称是:Proxy Pattern.还是老套路,先从名字上来看看.“代理”可以理 ...

随机推荐

  1. npm install报错node-sass@7.0.1 postinstall: `node scripts/build.js`

    在控制台执行 即可 npm config set sass_binary_site=https://npm.taobao.org/mirrors/node-sass

  2. 机器学习数据顺序随机打乱:Python实现

      本文介绍基于Python语言,实现机器学习.深度学习等模型训练时,数据集打乱的具体操作. 1 为什么要打乱数据集   在机器学习中,如果不进行数据集的打乱,则可能导致模型在训练过程中出现具有&qu ...

  3. 计算机网络 传输层协议TCP和UDP

    目录 一.传输层协议 二.tcp协议介绍 三.tcp报文格式 四.tcp三次握手 五.tcp四次挥手 六.udp协议介绍 七.常见协议和端口 八.有限状态机 一.传输层协议 传输层协议主要是TCP和U ...

  4. vscode 配置代码自动格式化加修复

    子曰:"工欲善其事,必先利其器", 编码必须的就是有一个顺手的ide,然而光有还不行,还要懂得配置,毕竟不同的团队代码规范不同,如目前用得较多的就是eslint,今天就顺便记录下v ...

  5. JavaScript原型与原型链深入理解

    原型: 每一个js 对象(null除外)都会和另一个对象相关联,"另一个"对象就被我们称之为'原型', 而每一个原型拥有一个prototype 属性指向原型对象(就是原型的实例)的 ...

  6. go语言中如何实现同步操作呢

    1. 简介 本文探讨了并发编程中的同步操作,讲述了为何需要同步以及两种常见的实现方式:sync.Cond和通道.通过比较它们的适用场景,读者可以更好地了解何时选择使用不同的同步方式.本文旨在帮助读者理 ...

  7. Clumpify:能使 Fastq 压缩文件再缩小 30% 并加速后续分析流程

    由于微信不允许外部链接,你需要点击文章尾部左下角的 "阅读原文",才能访问文中链接. Clumpify 是 BBMap 工具包中的一个组件,它与其他工具略有不同的是 Clumpif ...

  8. 算法基础(一):串匹配问题(BF,KMP算法)

    好家伙,学算法, 这篇看完,如果没有学会KMP算法,麻烦给我点踩 希望你能拿起纸和笔,一边阅读一边思考,看完这篇文章大概需要(20分钟的时间)   我们学这个算法是为了解决串匹配的问题 那什么是串匹配 ...

  9. 【HMS Core】Health Kit查询历史数据查询数据和返回数据不一致

    [问题描述] 查询一个月运动记录,只能查询到最早5月26的数据,但是华为健康app里的数据最早为5月8日,为什么会查询不到? [解决方案] 1.需要检查是否申请了历史数据权限,查询数据时,出于对用户的 ...

  10. [ARM 汇编]进阶篇—存储访问指令—2.3.2 多数据传输指令

    在 ARM 汇编中,多数据传输指令用于一次性从存储器中加载多个数据到寄存器组,或将寄存器组中的多个数据存储到存储器.这些指令通常用于高效地处理数组.结构体等数据结构.在本节中,我们将详细介绍 ARM ...