• 灵活运用设计模式之装饰变种


    灵活运用设计模式之装饰变种

    背景需求

      开篇我们先吹一下要实现什么目标:假定根据需求,用户需要通过企业名称来查询该企业名称下的法人、注册资本、经营范围等信息。
      假定目前有两个通道可通过企业名称来获取该企业的信息(后面可能会再增加多个接口):

    • 通过接口爬取工示系统网站获取(免费)(响应速度30秒内)
    • 通过第三方收费接口获取(收费)(响应速度1秒内)

    调用需求及思路

      用户查询要求录入企业名称后查询超时时间不超过60秒,所以为节约费用我们可以设定首先通过免费接口进行爬取,如果在限定的超时时间内获取不到企业信息,再通过第三方收费接口获取。

    初级代码实现

      一般初级代码实现可能设计如下:

    var 返回数据 = string.Empty;
    返回数据 = 免费查询接口(企业名称); //假定超时和无数据时返回null
    if(返回数据 == null)
    {
        返回数据 = 收费查询接口(企业名称);
    }
    

    如果这里有N多个免费查询接口要接入,那么:

    var 返回数据 = string.Empty;
    返回数据 = 免费查询接口1(企业名称); //假定超时和无数据时返回null
    if(返回数据 == null)
    {
        返回数据 = 免费查询接口2(企业名称);
    }
    if(返回数据 == null)
    {
        返回数据 = 免费查询接口3(企业名称);
    }
    if(返回数据 == null)
    {
        返回数据 = 免费查询接口4(企业名称);
    }
    if(返回数据 == null)
    {
        返回数据 = 免费查询接口N(企业名称);
    }
    //收费接口永远放在最后,万一我们的免费接口查询成功了呢 :)
    if(返回数据 == null)
    {
        返回数据 = 收费查询接口(企业名称);
    }
    

    这样做最大的问题就是程序偶合度太高,最明显的地方就是一旦接口有增减,都要来大改上面的主程序,依赖非常高。其它的问题不想再吐槽!

    代码实现的正确姿势

    "talk is cheap,show me the code":

    • 第一步 我们先设计一个带入参的抽象接口
        public abstract class IQuery
        {
           public abstract string GetQCCSelect(string creditCode, string subjectName);
        }
    
    • 第二步 我们得实现上面的抽象接口,因为这里我们要判断上一个方法执行返回的内容是否为空,恰好这个判断是共用的,所以我们引入了模板方法
        public abstract class AbsIQuery : IQuery
        {
            IQuery Iq;
    
            public AbsIQuery(IQuery iq)
            {
                Iq = iq;
            }
    
            public override string GetQCCSelect(string creditCode, string subjectName)
            {
                string ret = string.Empty;
                ret = Iq?.GetQCCSelect(creditCode, subjectName) ?? string.Empty;
                // 这里判断如果上一个查询方法查询超时或者返回为空,则进行下一个方法的查询
                if (string.IsNullOrEmpty(ret))
                {
                    ret = Excute(creditCode, subjectName);
                }
                return ret;
            }
            public abstract string Excute(string creditCode, string subjectName);
        }
    
    • 第三步 开始实现我们的N多个查询的各个方法,继承并实现AbsIQuery抽象类,假如目前只有两个接口,一个免费接口一个收费接口
      免费接口如下:
        public class GSXTSelect : AbsIQuery
        {
            public GSXTSelect(IQuery iq) : base(iq)
            {
            }
            public override string Excute(string creditCode, string subjectName)
            {
                string ret = string.Empty;
                string paramas = $"creditCode={creditCode}&subjectName={subjectName}";
                //假定我们这里用百度返回的值
                ret = HttpHelper.GetResponse("https://www.baidu.com", "POST", paramas);
                return ret;
            }
        }
    

    收费接口如下:

        public class QCCSelect : AbsIQuery
        {
            public QCCSelect(AbsIQuery iq) : base(iq)
            {
            }
    
            public override string Excute(string creditCode, string subjectName)
            {
                string ret = string.Empty;
                string paramas = $"creditCode={creditCode}&subjectName={subjectName}";
                ret = HttpHelper.GetResponse("https://xxxxx.xxxx.com/GetEnterpriceInfo", "POST", paramas);
                return ret;
            }
        }
    
    • 第四步 主程序调用如下:
        IQuery iq = new QCCSelect(new GSXTSelect(null)); //这一步可通过配置反射来实现,这样就不用当接口有增减的时候再来改这里了!
        string iqStr = iq.GetQCCSelect("", "阿里巴巴"); 
    

    总结

      如上,这样我们的程序就写完了,倘若过几天领导要求再加一个免费接口接入,我们怎么办呢?其实我们只需要做第三步,增加你想要增加的接口就可以了。比如要增加的接口名称就叫“免费接口N”,则:

        public class 免费接口N : AbsIQuery
        {
            public 免费接口N(AbsIQuery iq) : base(iq)
            {
            }
    
            public override string Excute(string creditCode, string subjectName)
            {
                string ret = string.Empty;
                string paramas = $"creditCode={creditCode}&subjectName={subjectName}";
                ret = HttpHelper.GetResponse("https://免费接口N的地址", "POST", paramas);
                return ret;
            }
        }
    

    最后,再主程序上面加上这个接口方法就可以了:

        IQuery iq = new QCCSelect(new GSXTSelect(new 免费接口N(null))); //这一步可通过配置反射来实现,这样就不用当接口有增减的时候再来改这里了!
        string iqStr = iq.GetQCCSelect("", "阿里巴巴"); 
    

    可以让我们清楚的看到:

    倘若要增加接口时只管 继承并实现AbsIQuery抽象类 就可以了,不关心其它任何逻辑判断,当接口增加完后,只需要在调用的地方再new一下我们的实现类就可以了,连调用参数都不用写。

    倘若要减少接口时,只需要在调用的地方把我们要去掉的实现类删除就可以了。

  • 相关阅读:
    《C++ Primer》学习笔记第2章 变量和基本类型
    Java学习笔记类的继承与多态特性
    Java的冒泡排序问题
    新起点,分享,进步
    MVC2中Area的路由注册实现
    了解一下new关键字实现阻断继承的原理
    利用Bing API开发的搜索工具(MVC+WCF)
    ASP.NET MVC中错误处理方式
    const和readonly内部区别
    WCF中校验参数的实现方式(一)
  • 原文地址:https://www.cnblogs.com/zh672903/p/11213458.html
Copyright © 2020-2023  润新知