在现实生活中,我们的笔记本电脑的工作电压大多数都是20V,而我国的家庭用电是220V,如何让20V的笔记本电脑能够工作在220V的电压下工作?答案:引入一个电源适配器,俗称变压器,有了这个电源适配器,生活用电和笔记本电脑即可兼容。

在软件开发中,有时候也会存在这种不兼容的情况,我们也可以像电源适配器一样引入一个称之为适配器的角色来协调这些存在不兼容的结构,这种设计方案即称之为适配器模式。

适配器模式(Builder) 学习难度:★★☆☆☆ 使用频率:★★★★☆

一、木有源码的算法库

Background : M公司在很久以前曾经开发了一个算法库,里面包含了一些常用的算法,例如排序和查找算法,在进行各类软件开发时经常需要重用该算法库中的算法。在为某学校开发教务管理系统时,开发人员发现需要对学生成绩进行排序和查找。该系统的设计人员已经开发了一个成绩操作接口IScoreOperation,在该接口中声明了排序方法Sort(int[])和查找方法Search(int[],int)。为了提高排序和查找的效率,开发人员决定重用算法库中的快速排序算法类QuickSort和二分查找算法类BinarySearch。但是,由于某些原因,现在M公司开发人员已经找不到该算法库的源代码,无法直接通过复制合粘贴操作来重用其中的代码;部分开发人员已经针对IScoreOperation接口编写代码,如果这时再要求对该接口修改或者要求大家直接使用QuickSort类和BinarySearch类将会导致大量代码需要修改。

因此,M公司开发人员面对这个没有远吗的算法库,遇到了一个幸福而又烦恼的问题:如何在既不修改现有接口又不需要任何算法库代码的基础上实现算法库的重用?  

  通过分析,不难得知,现在M公司面对的问题有点类似于我们在最开始提到的电压问题,成绩操作接口IScoreOperation有点类似于只支持20V电压的笔记本电脑,而算法库好比220V的家庭用电,这两部分都没法再进行修改,而且它们原本是两个完全不相关的结构。

  为了让IScoreOperation接口与已有算法库一起工作,让它们在同一个系统中能够兼容,最好的实现方法是增加一个类似电源适配器一样的适配器角色,通过适配器来协调这两个原本不兼容的结构。

二、适配器模式简介

2.1 适配器模式定义

  适配器模式的实现就是把客户类的请求转化为对应适配者的相应接口的调用。也就是说:当客户类调用适配器的方法时,在适配器类的内部将调用适配者类的方法,而这个过程对于客户类来说是透明的,客户类并不直接访问适配者类。因此,适配器让那些由于接口不兼容而不能交互的类可以一起工作。

适配器(Adapter)模式:将一个接口转换成客户希望的另一个接口,使接口不兼容的那些类可以一起工作。

2.2 适配器模式主要角色

  适配器模式一般包含以下3个角色:

  (1)Target(目标抽象类):目标抽象类定义了客户所需要的接口,可以是一个抽象类或接口,也可以是一个具体的类。

  (2)Adapter(适配器类):适配器可以调用另一个接口,作为一个转换器,对Adaptee和Target进行适配。适配器类是适配者模式的核心,在适配器模式中,它通过继承Target并关联一个Adaptee对象使二者产生联系。

  (3)Adaptee(适配者类):适配者即被适配的角色,它定义了一个已经存在的接口,这个接口需要适配,一般是一个具体类,包含了客户希望使用的业务方法,在某些情况下可能没有适配者类的源代码。

三、借助适配器重用算法库

3.1 解决方案结构图

  其中,IScoreOpertion接口充当抽象目标,QuickSort和BinarySearch类充当适配者,而OperationAdapter充当适配器。

3.2 具体实现

  (1)Target(目标抽象类):

    /// <summary>/// 目标接口:抽象成绩操作类/// </summary>public interface IScoreOperation{// 成绩排序int[] Sort(int[] array);// 成绩查找int Search(int[] array, int key);}

  (2)Adaptee(适配者类):

    /// <summary>/// 适配者A:快速排序类/// </summary>public class QuickSortHelper{public int[] QuickSort(int[] array){Sort(array, 0, array.Length - 1);return array;}public void Sort(int[] array, int p, int r){int q = 0;if (p < r){q = Partition(array, p, r);Sort(array, p, q - 1);Sort(array, q + 1, r);}}public int Partition(int[] array, int p, int r){int x = array[r];int j = p - 1;for (int i = p; i <= r - 1; i++){if (array[i] <= x){j++;Swap(array, j, i);}}Swap(array,j+1,r);return j + 1;}public void Swap(int[] array, int i, int j){int t = array[i];array[i] = array[j];array[j] = t;}}

  

    public class BinarySearchHelper{public int BinarySearch(int[] array, int key){int low = 0;int high = array.Length - 1;while (low <= high){int mid = (low + high) / 2;int midVal = array[mid];if (midVal < key){low = mid + 1;}else if (midVal > key){high = mid - 1;}else{return 1;   // 找到元素返回1
                }}return -1;  // 未找到元素返回-1
        }}

  (3)Adapter(适配器类):

    /// <summary>/// 适配器:成绩操作适配器类/// </summary>public class OperationAdapter : IScoreOperation{private QuickSortHelper sortTarget;private BinarySearchHelper searchTarget;public OperationAdapter(){sortTarget = new QuickSortHelper();searchTarget = new BinarySearchHelper();}public int Search(int[] array, int key){return searchTarget.BinarySearch(array, key);}public int[] Sort(int[] array){return sortTarget.QuickSort(array);}}

  (4)Client 客户端测试代码

    public class Client{public static void Main(string[] args){IScoreOperation operation = (IScoreOperation)AppConfigHelper.GetAdapterInstance();if (operation == null){return;}int[] scores = { 84, 76, 50, 69, 90, 91, 88, 96 };int[] result;int score;Console.WriteLine("测试成绩排序结果:");result = operation.Sort(scores);foreach (int s in result){Console.Write("{0},", s.ToString());}Console.WriteLine();Console.WriteLine("查找是否有90分的人:");score = operation.Search(scores, 90);if (score == -1){Console.WriteLine("抱歉,这个真没找到~~~");}else{Console.WriteLine("恭喜,的确存在90分选手~~~");}Console.WriteLine("查找是否有92分的人:");score = operation.Search(scores, 92);if (score == -1){Console.WriteLine("抱歉,这个真没找到~~~");}else{Console.WriteLine("恭喜,的确存在92分选手~~~");}Console.ReadKey();}}

  为了让系统具有良好的灵活性和可扩展性,引入了配置文件和AppConfigHelper类。

  其中,将具体的Adapter实例配置在配置文件中,如果需要使用其他的排序算法和查找算法类,可以增加一个新的适配器类,使用新的适配器来适配新的算法,原有代码无需修改。

<?xml version="1.0" encoding="utf-8" ?>
<configuration><appSettings><add key="AdapterName" value="Manulife.ChengDu.DesignPattern.Adapter.OperationAdapter, Manulife.ChengDu.DesignPattern.Adapter" /></appSettings>
</configuration>

  AppConfigHelper主要用于读取配置文件并通过反射生成实例,可以在不修改客户端代码地情况下使用新的适配器,其具体代码如下:

    public class AppConfigHelper{public static string GetAdapterName(){string factoryName = null;try{factoryName = System.Configuration.ConfigurationManager.AppSettings["AdapterName"];}catch (Exception ex){Console.WriteLine(ex.Message);}return factoryName;}public static object GetAdapterInstance(){string assemblyName = AppConfigHelper.GetAdapterName();Type type = Type.GetType(assemblyName);var instance = Activator.CreateInstance(type);return instance;}}

View Code

  编译并运行,结果如下图所示:

  

四、适配器模式小结

4.1 主要优点

  (1)将目标类和适配者类解耦,从而无须修改原有结构(只需新增一个适配器类)

  (2)增加了类的透明性(适配者类中的业务实现过程)和复用性(同一个适配者类可以在多个不同的系统中复用)

  (3)灵活性和可扩展性很好(借助配置文件和反射机制,可以方便地切换适配器,符合开闭原则)

4.2 应用场景

  (1)系统需要使用一些现有的类,而这些类的接口(例如方法名)不符合系统的需要,甚至没有这些类的源码。

  (2)想要创建一个可以复用的类,用于一些彼此之间没有太大关联的类,包括一些可能在将来引进的类一起工作。

参考资料

  刘伟,《设计模式的艺术—软件开发人员内功修炼之道》

作者:周旭龙

出处:http://edisonchou.cnblogs.com

本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接。

设计模式的征途—7.适配器(Adapter)模式相关推荐

  1. 设计模式学习笔记——适配器(Adapter)模式

    设计模式学习笔记--适配器(Adapter)模式 @(设计模式)[设计模式, 适配器模式, adapter, 适配器] 设计模式学习笔记适配器Adapter模式 基本介绍 适配器案例 类适配器模式 类 ...

  2. Ruby设计模式透析之 —— 适配器(Adapter)

    转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/9400153 此为Java设计模式透析的拷贝版,专门为Ruby爱好者提供的,不熟悉R ...

  3. 设计模式--适配器(Adapter)模式

    模式定义 将一个类的接口转换成客户希望的另一个接口,适配器模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作 类图 应用场景 1.当你希望使用某些现有类,但其接口与你的其他代码不兼容时: 2 ...

  4. java设计模式adapter_Java设计模式--适配器(Adapter)模式

    适配器模式把一个类的接口变换成客户端所期待的另一种接口,从而使原本因接口不匹配而无法在一起工作的两个类能够在一起工作. 适配器模式的用途 用电器做例子,笔记本电脑的插头一般都是三相的,即除了阳极.阴极 ...

  5. C++之适配器(Adapter)模式

    0. 简介 适配器模式是一种结构型设计模式, 它能将一个接口转换成客户希望的另一个接口,使接口不兼容的那些类可以一起工作,其别名为包装器(Wrapper). 根据适配器类与适配者类的关系不同,适配器模 ...

  6. Java设计模式透析之 —— 适配器(Adapter)

    转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/9400141 今天一大早,你的leader就匆匆忙忙跑过来找到你:"快,快 ...

  7. 打造炫酷通用的ViewPager指示器 Adapter模式适配所有 1

    ###1.概述 上一期我们已经写了一篇 打造炫酷通用的ViewPager指示器 - 玩转字体变色 可是这种效果虽然绚烂可以装装A和C之间,但是在实际的大多数效果中并不常见,只是在内涵段子中有这个效果而 ...

  8. 设计模式(五)适配器模式Adapter(结构型)

    设计模式(五)适配器模式Adapter(结构型) 1. 概述: 接口的改变,是一个需要程序员们必须(虽然很不情愿)接受和处理的普遍问题.程序提供者们修改他们的代码;系统库被修正;各种程序语言以及相关库 ...

  9. 漂亮的Adapter模式-体会RecyclerView的设计实现

    最近在研究设计模式的时候看到了Adapter模式,第一时间就想到了RecyclerView用到的Adapter,简单地走了一遍ReyclerView相关的源码,不得不感叹:设计得真的漂亮. 本文算不上 ...

  10. 适配接口 java_【Java 设计模式】接口型模式--Adapter(适配器)模式

    简介:[Java设计模式]接口型模式–Adapter(适配器)模式Adapter模式的宗旨就是:向客户提供接口,并使用现有的类所提供的服务,以满足客户的需求. 或者说,现在有classA的方法满足客户 ...

最新文章

  1. 天冷了,大家如果有往年的不穿的衣服别扔,寄给需要的人好吗?
  2. Android之四大组件(Activity)
  3. python的历史 常量 注释 基础数据类型等基本操作 和if 判断语句
  4. mysql给数据做排名_mysql给数据统计做排名
  5. [Spark][Python]sortByKey 例子
  6. 遍历 HashSet 的方法
  7. 因子分解(信息学奥赛一本通-T1210)
  8. java面向对象的教程_java面向对象入门教程
  9. 2020年5月机器视觉工作阶段性总结
  10. Linux属于开放代码,下面()操作系统是开放源代码的。
  11. 美学心得(第一百七十九集) 罗国正
  12. 电脑取消撤销快捷键是什么_都知道“撤消”快捷键是Ctrl Z,那“反撤消”是什么呢?...
  13. 我有一个梦想计算机工程师作文,我有一个梦想作文(通用10篇)
  14. 【python】基础网络爬虫教程
  15. 程序员非常好用的app
  16. Java 优秀博主 (合集)
  17. 一分钟知道屏幕分辨率、尺寸、PPI之间的关系!!!
  18. excel中vlookup函数的用法
  19. 最优化方法总结:公式解、数值优化、求解思想
  20. 慕容小匹夫 Unity3D移动平台动态读取外部文件全解析

热门文章

  1. windows7 shift+右键 “在此处打开命令窗口”
  2. bzoj3612 平衡 (dp)
  3. Helm 安装 nginx-ingress 的方法
  4. 剑指offer之【树的子结构】
  5. 空间目录Tomcat ShutDown出现 Insufficient space for shared memory file:
  6. 大话存储系列21——存储系统内部IO 上
  7. 移除单元格选中时的高亮显示状态
  8. Arturia Prophet V3 for Mac(多功能仿真音乐合成器)
  9. Give root password for maintenance (Or press Control-D to continue)
  10. iMazing六大主要功能介绍