基础介绍:

  想象这样一个场景,原项目中接口返回的数据是XML格式的数据,但现在来了一个新客户,它期望接口返回的数据类型为json格式的。

  想要实现要么就是改原有接口,但这样就违反了开闭原则,容易出现未知bug,影响到老客户的正常使用。

  而如果写一个适配器类也就是转换类(第三方类),将原本返回的XML格式数据转换成json格式数据,而具体数据是怎么来的则直接用原有接口方法就可以。

  新客户只需要调用适配器类就可以了,而老客户这边也不会进行任何修改处理。

  如果再有新的客户要求其他类型的返回,只需要在适配器类中增加相应的转换处理就可以了。

  再思考一个问题,现实生活中空调插头一般都是三头的,但如果家里只有两孔插座,那必然是插不进去的。

  以前老的办法那就是把三头插座掰掉一个,另外两个也掰直,这样做存在很大的安全隐患,而且有时并不能工作。

  而如果提供一个拥有三孔插座和两头插头的转换器的话,那空调可以先插在这个转换器上,然后这个转换器再插在插座上就可以了。

  本质并没有变,只是将二孔插座包装了一下,向外界提供了一个三孔插座的外观以供客户使用。

  适配的本质就是转换,将不满足使用条件的东西通过第三方类进行加工处理成可使用的东西。

  适配器模式(Apapter Pattern)是一种结构型设计模式,将一个类的接口转换成客户希望的另一个接口。适配器模式使得原本由于接口兼容而不能一起工作的那些类可以一起工作。  

  适配器模式用来解决现有对象与客户端期待接口不一致的问题。

  • 目标角色(Target):描述了其他类与客户端代码合作时必须遵循的协议。
  • 客户角色(Client):与符合Target接口的对象协同。
  • 被适配(服务类,功能类)(Adaptee):定义一个已经存在并已经使用的接口,这个接口需要适配。 客户端与其接口不兼容, 因此无法直接调用其功能。
  • 适配器(Adapter) :适配器模式的核心。适配器接受客户端通过适配器接口发起的调用,同时根据其内在逻辑调用对应服务类。客户端代码只需通过接口与适配器交互即可, 无需与具体的服务类耦合。

优缺点:

  • 单一职责原则:可以将接口或数据转换代码从主要业务逻辑中分离。
  • 开闭原则: 客户端接口只需适配器进行交互, 能在不修改现有代码的情况下在程序中添加新类型的适配器。
  • 通过适配器模式,可以使两个不兼容的接口协同工作,避免了修改现有代码的需要。
  • 提高了代码的复用性和灵活性,因为适配器可以重复使用,并且可以在不同的场景中使用。
  • 降低了系统的耦合度,适配器模式允许系统中的各个组件相互独立地演化。
  • 代码整体复杂度增加 :因为需要新增一系列接口和类。 有时直接更改服务类使其与其他代码兼容会更简单。

应用场景:

  系统需要复用现有类,但是接口又与复用环境要求不一致的情况。

  • 旧系统与新系统的兼容:可以使新系统能够无缝地与老旧系统进行通信
  • 第三方组件的集成:适配器可以将第三方组件的接口转换为符合我们系统需求的接口形式,从而能够顺利地集成到我们的系统中。
  • 多个类库之间的互操作:适配器模式可以起到桥梁的作用

创建方式:

  适配器模式有两种实现结构,对象适配器类适配器。

  试想一下,目前有一个三头插头的空调,需要一个三孔插座,但目前只有一个两孔插座。

  编写一个适配器来包装一下这个两孔插座,让用户可以使用这个空调。

  1. 类适配器

     1     /// <summary>
    2 /// 两孔插座---被适配者
    3 /// </summary>
    4 public class TwoHoleSocket
    5 {
    6 public void SpecificRequest()
    7 {
    8 Console.WriteLine("两孔插座");
    9 }
    10 }
    11
    12 /// <summary>
    13 /// 三孔插座---目标角色
    14 /// </summary>
    15 public interface IThreeHoleSocket
    16 {
    17 void Request();
    18 }
    19
    20 /// <summary>
    21 /// 适配器类提供了三孔插座的外观,但其本质是两孔插座
    22 /// </summary>
    23 public class PowerAdapter : TwoHoleSocket, IThreeHoleSocket
    24 {
    25 public void Request()
    26 {
    27 Console.WriteLine("提供三孔插座的外观");
    28 //执行两孔插座的功能
    29 this.SpecificRequest();
    30 }
    31 }
    32
    33 /// <summary>
    34 /// 客户端
    35 /// </summary>
    36 class Client
    37 {
    38 static void Main(string[] args)
    39 {
    40 //客户端可以通过适配器来使用这个两孔插座了(因为外观已经是三孔的了)
    41 IThreeHoleSocket threeHoleSocket = new PowerAdapter();
    42 threeHoleSocket.Request();
    43 Console.ReadKey();
    44 }
    45 }

    TwoHoleSocket类代表原有的两孔插座,IThreeHoleSocket接口来规范三孔插座的外观。

    PowerAdapter类代表适配器,将两孔插座赋予三孔插座的外观。

    这样用户就可以使用这个适配器来使用这个三头插头的空调了。

    从实例中可以看出,类适配器只要是用继承来实现的,但如果有很多个类进行适配,这个方式就不支持了。

  2. 对象适配器

     1     /// <summary>
    2 /// 两孔插座---被适配者
    3 /// </summary>
    4 public class TwoHoleSocket
    5 {
    6 public void SpecificRequest()
    7 {
    8 Console.WriteLine("两孔插座");
    9 }
    10 }
    11
    12 /// <summary>
    13 /// 三孔插座---目标角色
    14 /// </summary>
    15 public class ThreeHoleSocket
    16 {
    17 // 客户端需要的方法
    18 public virtual void Request()
    19 {
    20 //具体实现
    21 }
    22 }
    23
    24 /// <summary>
    25 /// 适配器类提供了三孔插座的外观,但其本质是两孔插座
    26 /// </summary>
    27 public class PowerAdapter : ThreeHoleSocket
    28 {
    29 //引用两孔插座的实例,从而将客户端与TwoHoleSocket联系起来
    30 public TwoHoleSocket twoHoleSocket = new TwoHoleSocket();
    31 public override void Request()
    32 {
    33 Console.WriteLine("提供三孔插座的外观");
    34 this.Request();
    35 //执行两孔插座的功能
    36 twoHoleSocket.SpecificRequest();
    37 }
    38 }
    39
    40 /// <summary>
    41 /// 客户端
    42 /// </summary>
    43 class Client
    44 {
    45 static void Main(string[] args)
    46 {
    47 //客户端可以通过适配器来使用这个两孔插座了(因为外观已经是三孔的了)
    48 ThreeHoleSocket threeHoleSocket = new PowerAdapter();
    49 threeHoleSocket.Request();
    50 Console.ReadKey();
    51 }
    52 }

    从实例中可以看出,对象适配器其实就是在适配器类中创建了一个被适配者的实例,从而将两者联系在一起。

    这种方式采用 “对象组合”的方式,更符合松耦合。

总结:

  总而言之,适配器就是一个第三方类,将不合时宜的东西转换成符合心意的工具类。

  本质就是转换。

  

c#中适配器模式详解的更多相关文章

  1. winxp计算机管理中服务详解

    winxp计算机管理中服务详解01 http://blog.sina.com.cn/s/blog_60f923b50100efy9.html http://blog.sina.com.cn/s/blo ...

  2. cocos2dx常见的46中+22中动作详解

    cocos2dx常见的46中+22中动作详解 分类: iOS2013-10-16 00:44 1429人阅读 评论(0) 收藏 举报 bool HelloWorld::init(){    ///// ...

  3. Android中Context详解 ---- 你所不知道的Context

    转自:http://blog.csdn.net/qinjuning/article/details/7310620Android中Context详解 ---- 你所不知道的Context 大家好,  ...

  4. iOS中-Qutarz2D详解及使用

    在iOS中Qutarz2D 详解及使用 (一)初识 介绍 Quartz 2D是二维绘图引擎. 能完成的工作有: 绘制图形 : 线条\三角形\矩形\圆\弧等 绘制文字 绘制\生成图片(图像) 读取\生成 ...

  5. 【转】declare-styleable的使用(自定义控件) 以及declare-styleable中format详解

    原文网址:http://www.cnblogs.com/622698abc/p/3348692.html declare-styleable是给自定义控件添加自定义属性用的 1.首先,先写attrs. ...

  6. Python中dict详解

    from:http://www.cnblogs.com/yangyongzhi/archive/2012/09/17/2688326.html Python中dict详解 python3.0以上,pr ...

  7. 【转】 java中HashMap详解

    原文网址:http://blog.csdn.net/caihaijiang/article/details/6280251 java中HashMap详解 HashMap 和 HashSet 是 Jav ...

  8. java中HashMap详解(转)

    java中HashMap详解 博客分类: JavaSE Java算法JDK编程生活       HashMap 和 HashSet 是 Java Collection Framework 的两个重要成 ...

  9. java集合(2)- java中HashMap详解

    java中HashMap详解 基于哈希表的 Map 接口的实现.此实现提供所有可选的映射操作,并允许使用 null 值和 null 键.(除了非同步和允许使用 null 之外,HashMap 类与 H ...

  10. PHP中Trait详解及其应用

    w PHP中Trait详解及其应用 - 开发者日常 - SegmentFaulthttps://segmentfault.com/a/1190000008009455

随机推荐

  1. 【最新】Delphi XE7 绿色版下载,亲测可用!

    最后更新时间 2017-12-05. 本文整理自2ccc盒子iny的帖子 → 链接到原贴 破解 → 链接 一.绿色版介绍 绿色版除了不包含 FastReport(RAD Studio自带的FastRe ...

  2. [Spring+SpringMVC+Mybatis]框架学习笔记(九):Mybatis主配置文件和映射文件

    第9章 Mybatis主配置文件和映射文件 9.1 用Mybatis进行开发的两种方式 在正式的开发环境中用Mybatis进行开发有两种方式: 1)原始的接口和实现类的方式 缺点: 重复代码太多,sq ...

  3. Linux 中设备的分类及网络设备接口路径

    设备分类 字符设备 块设备 网络设备 参考文档: 手把手教Linux驱动 网络设备位置 [root@localhost ~]# cd /sys/class/net/ [root@localhost n ...

  4. CMDB 相关

    CMDB 术语 CI(配置项) 配置管理解决方案(如CMDB)中的基本有形或无形实体. 为了交付IT服务而需要管理的任何组件. 通常包括IT服务.硬件.软件.架构.人员和正式文档(如流程文档和sla) ...

  5. 论文解读(BERT-DAAT)《Adversarial and Domain-Aware BERT for Cross-Domain Sentiment Analysis》

    论文信息 论文标题:Adversarial and Domain-Aware BERT for Cross-Domain Sentiment Analysis论文作者:论文来源:2020 ACL论文地 ...

  6. vulnhub_me and my grilfriend

    解题步骤 主机nmap扫描,开放22和80端口 访问该ip,发现只能本地访问 查看源代码,提示需要使用x-forwarded-for的请求头,可以在burp suite中每次添加一个请求头,也可以使用 ...

  7. Node: 将时间戳转换成日期并分组

    // 对时间戳按日期进行分组 let moment = require('moment') let timestamp_array = [ 1645059333000, 1613523333000, ...

  8. FreeSWITCH通过mod_mariadb原生连接MySQL

    前言 根据官方更新说明(https://freeswitch.org/confluence/display/FREESWITCH/FreeSWITCH+1.10.x+Release+notes),从1 ...

  9. 记通过mysql数据库成功入侵到服务器内部的渗透实战

    1,在成功进入mysql到数据库之后,可以使用select user();命令,查看当前的用户,如果为root,则可以执行下一步操作.不为root,则需要通过其他方法提权. 2, 使用show var ...

  10. 基于C#的无边框窗体阴影绘制方案 - 开源研究系列文章

    今天介绍无边框窗体阴影绘制的内容. 上次有介绍使用双窗体的方法来显示阴影,这次介绍使用API函数来进行绘制.这里使用的是Windows API函数,操作系统的窗体也是用的这个来进行的绘制. 1. 项目 ...