基础介绍:

  想象这样一个场景,原项目中接口返回的数据是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. Hexo博客Next主题valine评论系统邮件提醒

    简介 Valine:一款快速.简洁且高效的无后端评论系统. Valine-Admin Github 项目地址,具体教程以 最新版 为准 Valine-Admin项目地址 简介 Valine Admin ...

  2. http方式内网搭建CDH6.3.2与部分组件优化

    Cloudera_Manager_6.3.2安装配置文档 1. 配置准备 Cloudera Manager (简称CM)用于管理CDH6集群,可进行节点安装.配置.服务配置等,提供Web窗口界面提高了 ...

  3. C/C++八大排序

    排序 排序有内部排序和外部排序,内部排序是数据记录在内存中进行排序,而外部排序是因排序的数据很大,一次不能容纳全部的排序记录,在排序过程中需要访问外存. 按照难易程度排序,八大排序算法可以从简单到复杂 ...

  4. 使用 Go 语言实现二叉搜索树

    原文链接: 使用 Go 语言实现二叉搜索树 二叉树是一种常见并且非常重要的数据结构,在很多项目中都能看到二叉树的身影. 它有很多变种,比如红黑树,常被用作 std::map 和 std::set 的底 ...

  5. [selenium]浏览器基本操作

    前言 版本: python:3.9 selenium:4.1.5 浏览器:firefox 创建浏览器对象 from selenium import webdriver driver = webdriv ...

  6. 1.创建一个类,类A中定义了一个方法,该方法能接受3个参数根据参数判断是做加法还是减法并返回计算结果;

    class A: def cal(self,x,y,z): if z=='+': return x+y if z=='-': return x-y else: print('error') a=A() ...

  7. 使用canvas(2d)+js实现一个简单的傅里叶级数绘制方波图

    先看效果 查看页面右下角,嘿嘿 简要说明 创建具有不同半径与角速度的圆集合:(截图中展现的效果为5个,代码是30个,运行后效果会不同) const getCircles = (N = 10) => ...

  8. 聊聊JDK1.0到JDK20的那些事儿

    1.前言 最近小组在开展读书角活动,我们小组选的是<深入理解JVM虚拟机>,相信这本书对于各位程序猿们都不陌生,我也是之前在学校准备面试期间大致读过一遍,emm时隔多日,对里面的知识也就模 ...

  9. 领域驱动设计(DDD):三层架构到DDD架构演化

    三层架构的问题 在前文中,我从基础代码的角度探讨了如何运用领域驱动设计(DDD)来实现高内聚低耦合的代码.本篇文章将从项目架构的角度,继续探讨三层架构与DDD之间的演化过程,以及DDD如何优化架构的问 ...

  10. React仿大众点评外卖app

    主要使用技术: react react-router4 redux: action.reducer.store管理数据 fetch: 进行数据交互 prismjs : 页面嵌入代码,高亮显示插件 bu ...