设计模式的艺术之道--适配器模式

C#实现适配器模式解析
本文介绍了适配器模式的概念,通过C#代码展示了如何在无法修改原有接口的情况下,利用适配器模式实现算法库的重用。适配器模式通过创建一个适配器类,将不兼容的接口转换为客户期望的接口,从而让两个不兼容的类能够协同工作。

设计模式的艺术之道–适配器模式

声明:本系列为刘伟老师博客内容总结(http://blog.youkuaiyun.com/lovelion),博客中有完整的设计模式的相关博文,以及作者的出版书籍推荐

本系列内容思路分析借鉴了刘伟老师的博文内容,同时改用C#代码进行代码的演示和分析(Java资料过多 C#表示默哀).

本系列全部源码均在文末地址给出。

本系列开始讲解结构型模式,关注如何将现有类或对象组织在一起形成更加强大的结构。
不同的结构型模式从不同的角度组合类或对象,它们在尽可能满足各种面向对象设计原则的同时为类或对象的组合提供一系列巧妙的解决方案。

  • 类结构型模式
    关心类的组合,由多个类组合成一个更大的系统,在类结构型模式中一般只存在继承关系和实现关系
  • 对象结构型模式
    关心类与对象的组合,通过关联关系,在一个类中定义另一个类的实例对象,然后通过该对象调用相应的方法

7种常见的结构型模式

这里写图片描述

适配器模式

1.1定义

  • 适配器模式 (Adapter Pattern):将一个类的接口转换成客户希望的另一个接口。适配器模式让那些接口不兼容的类可以一起工作。
  • 不兼容:生活用电220V  笔记电脑20V 引入 AC Adapter(交流电适配器)
  • 电脑显卡输出HDMI 显示器VGA接口 买一个HDMI转VGA转接头

1.2情景实例

问题描述
- 没有源码的算法库
年底了,菜鸟软件公司也有少部分人离职,由于工作交接的疏忽,开发人员已经找不到ScoreOperation算法库的源代码(里边实现了排序方法Sort(int[]) 和查找方法Search(int[], int)),现在需要进行性能改进,重用之前QuickSort(int[])方法和BinarySearch (int[], int)方法,目前无法直接通过复制和粘贴操作来重用其中的代码;而且部分开发人员已经针对ScoreOperation接口编程,如果再要求对该接口进行修改或要求大家直接使用QuickSortClass类和BinarySearchClass类将导致大量代码需要修改。
开发人员面对这个没有源码的算法库,遇到一个棘手的问题:如何在既不修改现有接口又不需要任何算法库代码的基础上能够实现算法库的重用?
这里写图片描述

初步思路
我们需要ScoreOperation接口能够和已有算法库一起工作,让它们在同一个系统中能够兼容,最好的实现方法是增加一个类似电源适配器一样的适配器角色,通过适配器来协调这两个原本不兼容的结构。引入适配器模式。

UML类图
这里写图片描述
实例关键代码

namespace Adapter
{
    interface ScoreOperation 
    {
        int[] Sort(int[] array); //成绩排序
        int Search(int[] array, int key); //成绩查找
    }
    class BinarySearchClass
    {
        public int BinarySearch(int[] array, int key) 
        {
           //二分查找省略  请看源代码
        }
    }
    class QuickSortClass 
    {
        public int[] QuickSort(int[] array) 
        {
        //快速排序实现 省略  请看源代码
        }
    }
    class OperationAdapter : ScoreOperation
    {
        //继承自抽象接口的适配者类
        private QuickSortClass sortObj; //定义适配者QuickSortClass对象
        private BinarySearchClass searchObj; //定义适配者BinarySearchClass对象

        public OperationAdapter() 
        {
            sortObj = new QuickSortClass();
            searchObj = new BinarySearchClass();
        }

        public int[] Sort(int[] array) 
        {
            return sortObj.QuickSort(array); //调用适配者类QuickSortClass的排序方法
        }

        public int Search(int[] array, int key) 
        {
            return searchObj.BinarySearch(array, key); //调用适配者类BinarySearchClass的查找方法
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            ScoreOperation operation;  //针对抽象目标接口编程

            //读取配置文件
            string adapterType = ConfigurationManager.AppSettings["adapter"];
            //反射生成对象
            operation = (ScoreOperation)Assembly.Load("Adapter").CreateInstance(adapterType);

            int[] scores = {84,76,50,69,90,91,88,96}; //定义成绩数组
            int[] result;
            int score;
            Console.WriteLine("成绩排序结果:");
            result = operation.Sort(scores);

            //遍历输出成绩
            foreach (int i in result) 
            {
                Console.Write(i + ",");
            }
            Console.WriteLine();

            Console.WriteLine("查找成绩90:");
            score = operation.Search(result,90);
            if (score != -1) 
            {
                 Console.WriteLine("找到成绩90。");
            }
            else 
            {
                Console.WriteLine("没有找到成绩90。");
            }
            Console.WriteLine("查找成绩92:");
            score = operation.Search(result,92);
            if (score != -1) 
            {
                 Console.WriteLine("找到成绩92。");
            }
            else 
            {
                Console.WriteLine("没有找到成绩92。");
            }
            Console.Read();
        }
    }
}

1.3模式分析

动机和意图

  • 软件开发:
    存在不兼容的结构,例如方法名不一致,引入适配器模式,使得不改变原有客户端调用,转变使用新的方法

一般结构

  • 适配器模式包含三个角色:
  • Target(目标抽象类) 客户端需要调用 (原本目标)目标的方法
  • Adapter(适配器类) 使用原本目标的方法接口,但是采用新的目标的实现
  • Adaptee(适配者类) 客户端要更改的新的目标

    适配者模式两种类型
    类适配器

    这里写图片描述

    对象适配器

    这里写图片描述

  • 类适配器模式和对象适配器模式最大的区别在于适配器和适配者之间的关系不同

  • 对象适配器模式中适配器和适配者之间是关联关系
  • 类适配器模式中适配器和适配者是继承关系

改进的优点

  • 目标类和适配者类解耦,通过引入一个适配器类来重用现有的适配者类,无须修改原有结构
  • 增加了类的透明性(封装性隐藏性 你看不到他但是可以用它)和复用性,提高了适配者的复用性,同一个适配者类可以在多个不同的系统中复用
  • 一个对象适配器可以适配多个适配者,简化对外接口

现存的缺点

  • 类适配器模式:
  • (1) 一次最多只能适配一个适配者类,不能同时适配多个适配者;
  • (2) 适配者类不能为最终类;
  • (3) 目标抽象类只能为接口,不能为类(C#类不支持多继承)
  • 对象适配器模式:
  • 在适配器中置换适配者类的某些方法比较麻烦

优化空间
在对象适配器的使用过程中,如果在适配器中同时包含对目标类和适配者类的引用,适配者可以通过它调用目标类中的方法,目标类也可以通过它调用适配者类中的方法,那么该适配器就是一个双向适配器(代码见源文件)
这里写图片描述
缺省适配器
当不需要实现一个接口所提供的所有方法时,可先设计一个抽象类实现该接口,并为接口中每个方法提供一个默认实现(空方法),那么该抽象类的子类可以选择性地覆盖父类的某些方法来实现需求
这里写图片描述
在缺省适配器模式中,包含如下三个角色:
● ServiceInterface(适配者接口):它是一个接口,通常在该接口中声明了大量的方法。
● AbstractServiceClass(缺省适配器类):它是缺省适配器模式的核心类,使用空方法的形式实现了在ServiceInterface接口中声明的方法。通常将它定义为抽象类,因为对它进行实例化没有任何意义。
● ConcreteServiceClass(具体业务类):它是缺省适配器类的子类,在没有引入适配器之前,它需要实现适配者接口,因此需要实现在适配者接口中定义的所有方法,而对于一些无须使用的方法也不得不提供空实现。在有了缺省适配器之后,可以直接继承该适配器类,根据需要有选择性地覆盖在适配器类中定义的方法。

适用场景
(1) 系统需要使用一些现有的类,而这些类的接口不符合系统的需要,甚至没有这些类的源代码。
(2)创建一个可以重复使用的类,用于和一些彼此之间没有太大关联的类。
举例:电源插座的转换 手机充电器的转换 电脑显卡转接头

实例源代码
GitHub地址
百度云地址:链接: https://pan.baidu.com/s/1dFs93pR 密码: 3x97

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值