c#设计模式(6)——适配器模式

一、引言

     适配器模式(Adapter Pattern)是作为两个不兼容的接口之间的桥梁。这种类型的设计模式属于结构型模式,它结合了两个独立接口的功能。

     这种模式涉及到一个单一的类,该类负责加入独立的或不兼容的接口功能。举个真实的例子,读卡器是作为内存卡和笔记本之间的适配器。您将内存卡插入读卡器,再将读卡器插入笔记本,这样就可以通过笔记本来读取内存卡。

     接下来要说个例子来演示适配器模式的使用。其中我们一直在使用sqlserver进行增删查改的操作,突然某一天,感觉性能不行了,想替换成redis这种nosql的增删查改的方式,但是redis的帮助类的并没有和sqlserver查询类的接口命名一致,直接替换成本大,这时就需要一个中间层来适配,使得原来sqlserver的数据库操作无缝对接redis数据库操作。

二、介绍

    2.1 定义 

      下面让我们看看适配器的定义,适配器模式——把一个类的接口变换成客户端所期待的另一种接口,从而使原本接口不匹配而无法一起工作的两个类能够在一起工作。适配器模式有类的适配器模式和对象的适配器模式两种形式,下面我们先来描述一下类适配器模式。

    2.2 类适配器

      1. 在说适配器前,先展示一下sqlserver帮助类的实现。首先,先定义统一的增删查改帮助类接口。

     /// <summary>
    /// sql帮助抽象类
    /// </summary>
    public interface IHelper
    {
        void Query<T>();

        void Add<T>();

        void Update<T>();

        void Delete<T>();
    }

  2.接着就是sqlserver帮助类实现IHelper接口.

public class SqlServerHelper : IHelper
    {
        public SqlServerHelper()
        {
            Console.WriteLine($"{this.GetType().Name} 被构造");
        }
        public void Add<T>()
        {
            Console.WriteLine($"{this.GetType().Name}的Add正在添加数据");
        }

        public void Delete<T>()
        {
            Console.WriteLine($"{this.GetType().Name}的Delete正在删除数据");
        }

        public void Query<T>()
        {
            Console.WriteLine($"{this.GetType().Name}的Query正在查询数据");
        }

        public void Update<T>()
        {
            Console.WriteLine($"{this.GetType().Name}的Update正在更新数据");
        }
    }

  3.sqlserver一直用得好好的,现在业务升级了,数据库撑不住了,关系型数据库性能堪忧,Redis这种nosql很好,但是有个问题Redis有自定义的帮助类,如果需要升级使用Redis,不能直接替换sqlserver的帮助类的接口方法;因为RedisHelper没有实现IHelper接口;遇到一个想要放一起使用但是却不能一起使用的问题。这时我们的适配器就要登场了,先演示一下类适配器。

   

    /// <summary>
    /// redis帮助类,由于执行方法与sql的执行方法不一致,需要适配
    /// </summary>
    public class RedisHelper
    {
        public RedisHelper()
        {
            Console.WriteLine($"{this.GetType().Name} 被构造");
        }

        public void RedisAdd<T>()
        {
            Console.WriteLine($"{this.GetType().Name}的RedisAdd正在添加数据");
        }

        public void RedisDelete<T>()
        {
            Console.WriteLine($"{this.GetType().Name}的RedisDelete正在删除数据");
        }

        public void RedisQuery<T>()
        {
            Console.WriteLine($"{this.GetType().Name}的RedisQuery正在查询数据");
        }

        public void RedisUpdate<T>()
        {
            Console.WriteLine($"{this.GetType().Name}的RedisUpdate正在更新数据");
        }
    }

  

    /// <summary>
    /// 类适配器
    /// </summary>
    public class RedisClassHelper : RedisHelper, IHelper
    {
        // 继承实现了让IHelper 和Redis不兼容的事儿---适配器的一种;
        // 继承:
        // 1.因为是强继承,具有侵入性
        // 2.RedisClassHelper只能为RedisHelper服务;

        public void Add<T>()
        {
            base.RedisAdd<T>();
        }

        public void Delete<T>()
        {
            base.RedisDelete<T>();
        }

        public void Query<T>()
        {
            base.RedisQuery<T>();
        }

        public void Update<T>()
        {
            base.RedisUpdate<T>();
        }
    }

 

  class Program
    {

        static void Main(string[] args)
        {
             // sqlserver查询
            IHelper sqlServerHelper = new SqlServerHelper();
            sqlServerHelper.Add<DesignPatternStructure>();
            sqlServerHelper.Update<DesignPatternStructure>();
            sqlServerHelper.Query<DesignPatternStructure>();
            sqlServerHelper.Delete<DesignPatternStructure>();

            //现在业务升级了,数据库撑不住了,关系型数据库性能堪忧
            //Nosql == Redis很好----Redis的帮助类库--ServiceStack
            //需要升级使用Redis;----不能直接换了;因为RedisHelper没有实现IHelper接口;
            //遇到一个想要放一起使用但是却不能一起使用的问题;
            //这时就需要一个适配器了

            //类适配器
            //继承实现了让IHelper 和Redis不兼容的事儿---适配器的一种;
            //继承:
            //1.因为是强继承,具有侵入性
            //2.RedisClassHelper只能为Redishelper服务;
            IHelper redisClassHelper = new RedisClassHelper();
            redisClassHelper.Add<DesignPatternStructure>();
            redisClassHelper.Update<DesignPatternStructure>();
            redisClassHelper.Query<DesignPatternStructure>();
            redisClassHelper.Delete<DesignPatternStructure>();
        }
    }

  

 2.2 对象适配器

         4. 以上就是类适配器的实现,但是大家都发现了一个问题,就是虽然解决RedisHelper和IHelper不兼容的问题,但是因为是强继承,具有侵入性RedisClassHelper只能为Redishelper服务,而且想要匹配一      个类以及所有它的子类时,类的适配器模式就不能胜任了;为了解决这个问题,多了一种对象适配器,使得适配类可以兼容多个不同的对象。

         为了证明这一点,我写一个继承了RedisHelper类的子类

         

  public class RedisChildHelper: RedisHelper
    {
    }

  然后我写个对象适配器

    /// <summary>
    /// 对象适配器
    /// </summary>
    public class RedisObjHelper : IHelper
    {
        private RedisHelper _redisHelper = null;
        /// <summary>
        /// 构造函数方式注入
        /// 在实例化的时候,必须传入----就可以保障需要适配的对象不会为null
        /// </summary>
        /// <param name="redisHelper"></param>
        public RedisObjHelper(RedisHelper redisHelper)
        {
            _redisHelper = redisHelper;
        }

        public void SetRedisHelper(RedisHelper redisHelper)
        {
            _redisHelper = redisHelper;
        }

        public void Add<T>()
        {
            _redisHelper.RedisAdd<T>();
        }

        public void Delete<T>()
        {
            _redisHelper.RedisDelete<T>();
        }

        public void Query<T>()
        {
            _redisHelper.RedisQuery<T>();
        }

        public void Update<T>()
        {
            _redisHelper.RedisUpdate<T>();
        }
    }

  5.演示一下对象适配器的实现

   

class Program
    {

        static void Main(string[] args)
        {
            //对象适配器
            //为什么说组合优于继承呢?
            //1.没有侵入性
            //2.可以为多个类型服务
            //3.相对来说要更加灵活一点
            //IHelper redisObjHelper = new RedisObjHelper(new RedisHelper());
            IHelper redisChildHelper = new RedisObjHelper(new RedisChildHelper());
            redisObjHelper.Add<DesignPatternStructure>();
            redisObjHelper.Update<DesignPatternStructure>();
            redisObjHelper.Query<DesignPatternStructure>();
            redisObjHelper.Delete<DesignPatternStructure>();
        }
    }

  

三、适配器模式的优缺点

     类适配器模式:

      1.优点:

             可以在不修改原有代码的基础上来复用现有类,很好地符合 “开闭原则”

             可以重新定义(被适配的类)的部分行为.

            仅仅引入一个对象,并不需要额外的字段来引用RedisHelper实例(这个即是优点也是缺点)

      2.缺点:

           采用了 “多继承”的实现方式,带来了不良的高耦合。

     对象适配器模式:

       1.优点:可以在不修改原有代码的基础上来复用现有类,很好地符合 “开闭原则”,采用 “对象组合”的方式,更符合松耦合,以兼容多个不同的对象

                        

posted @ 2020-09-28 15:44  小贤k  阅读(217)  评论(0编辑  收藏  举报