zoukankan      html  css  js  c++  java
  • .NET责任链模式(混合单例模式,模板方法模式)-----制作与扩展能力验证

    .NET责任链模式、单例模式、模板方法模式混用

     

    前言

      哇,看到题目挺长的,这个组合型的东西,到底能干啥呢?本篇文章来一起琢磨琢磨,这两天为了团队的软件赶工,我负责的那一块叫:插件管理器。我们团队的成员用的语言还是挺分散的,本人C#,队长VB.NET,还有其他成员写易语言等,系统的功能插件是我们分开写的,各自用各自的喜欢的语言写各个功能模块的插件,最后用我开发的插件管理器把所有的插件整合到一起。这让我很头疼啊,一个C#版的插件,一个VB.NET版的插件,一个易语言的插件,如果有新成员加入,又来个Python版的插件,叫我如何是好。最普通、最烂的处理方法就是:写很多版本的读取器,然后使用if来根据插件语言使用对应该版本的读取器读取信息,哇,这如果来十几种语言,岂不是坑爹。可能有人会说:引入Kernel32能解决非.NET语言的插件读取吧。确实目前使用了这种方案,能兼容易语言,.NET语言就使用.NET的插件Dll读取方式,但是还不确定Kernel32能不能解决任何语言的插件。所以为了让自己有个后路,我结合题目所说的三种设计模式,写了一个模板,下面看这个模板能干嘛,为什么要这样用。如果有地方使用得不恰当的,希望各位朋友们强拍,我会努力学习改正,如果觉得可以的,点个推荐,谢谢~

     

    框架展示与说明

                                           

      大家看下类图,下面分别介绍各个类的职责。Plugin类是插件的数据结构类,PluginType是一个枚举,它的内容是定义了所有插件的类型,例如DotNet,Python等,扩展的时候需要修改该枚举。然后剩下的就是本章的重点了,用户代码Client使用IPluginAnalyzerable接口来读取插件信息,该接口有两个实现类,一个是PluginAnalyzer(抽象类,定义各个语言的读取器的公共部分),该类实现模板方法模式和责任链模式,让处理命令能在其子类之间互相推卸责任,其子类目前有两个,分别是DotNet,Python的具体读取器。最后一个类ComponentAnalyzer担任封装职责,将责任链初始化好,自己实现单例模式,提供给用户代码调用。所以,最后的效果是:获取ComponentAnalyzer的实例,调用其中一个方法,该方法调用具体读取器链,最后哪个读取器处理了请求,用户是不需要知道的,大概思路就是这样。

    实现过

      本实现过程只是模板的实现,具体应用到项目中还需要做出相应的改变。

      事不宜迟,我们先实现Plugin类和PlugType枚举:

        Plugin:

    class Plugin
        {
            public Plugin(PluginType type,String pluginPath)
            {
                this.BelongType = type;
                this.PluginPath = pluginPath;
            }
            public PluginType BelongType { set; get; }
            public String PluginPath { set; get; }
        }

        PlugType:

    enum PluginType
        {
            DotNet=0,
            Python=1,
        }

      实现完两个基本的类型以后,然后就来看下本篇的重头戏,我会边贴代码边附加上帮助理解的说明。首先从最底层的IPluginAnalyzerable开始:

    interface IPluginAnalyzerable
        {
             void Analyze(Plugin plugin);
        }

      用户代码就是使用该接口的Analyze方法来处理传入的插件的,再下一层有两个类,一个是抽象类PluginAnalyzer,一个是ComponentAnalyzer。

    abstract class PluginAnalyzer:IPluginAnalyzerable
        {
            public PluginAnalyzer(PluginType type)
            {
                this.analyzerType = type;
            }
            protected PluginType analyzerType;
    
            public void Analyze(Plugin plugin)
            {
                if (plugin.BelongType == this.analyzerType)
                {
                    String author = GetAuthor(plugin);
                    String version = GetVersion(plugin);
                    Console.WriteLine(String.Format("
    分析者:{0},插件类型:{1} 
    {2}
    {3}", 
                        this.GetType().Name,plugin.BelongType,author, version));
                }
                else
                {
                    if (nextAnalyzer != null)
                    {
                        nextAnalyzer.Analyze(plugin);
                    }
                }
            }
    
            private PluginAnalyzer nextAnalyzer;
            public PluginAnalyzer NextAnalyzer
            {
                set
                {
                    this.nextAnalyzer = value;
                }
                get 
                {
                    return this.nextAnalyzer;
                }
            }
    
            protected abstract String GetAuthor(Plugin plugin);
            protected abstract String GetVersion(Plugin plugin);
        }

      解读:

      每一个继承本类的具体类都有两个字段

        1:所属类型(PluginType枚举),变量名为analyzerType。  

        2:下一个分析者(PluginAnalyzer),也就是兄弟类(同样继承PluginAnalyzer)。

      每一个继承本类的具体类都需要重写两个方法GetAuthor和GetVersion,这两个方法将会在模板方法Analyzer内部被使用。

      模板方法Analyzer首先判断传进来的插件类型是否和自身可以处理的类型相同,如果相同则调用自身的方法处理,如果不同则把处理权推给自己的下一位分析者。这样就完成了具体架构的搭建了。

      

      然后就是具体读取器类了,各自有各自的处理相同任务的方式。都继承PluginAnalyzer

        DotNetPluginAnalyzer(该类是处理.NET插件的读取器)

    class DotNetPluginAnalyzer:PluginAnalyzer
        {
            public DotNetPluginAnalyzer(PluginType type) 
                : base(type) 
            { }
            public DotNetPluginAnalyzer()
                : base(PluginType.DotNet)
            { }
            protected override string GetAuthor(Plugin plugin)
            {
                return "DotNet的插件,作者名为:Jarvin";
            }
    
            protected override string GetVersion(Plugin plugin)
            {
                return "DotNet的插件,版本号为:!!!V2014!!";
            }
        }

        PythonPluginAnalyzer(该类是处理Python插件的读取器)

    class PythonPluginAnalyzer:PluginAnalyzer
        {
            public PythonPluginAnalyzer(PluginType type) 
                : base(type) 
            { }
            public PythonPluginAnalyzer()
                : base(PluginType.Python)
            { }
            protected override string GetAuthor(Plugin plugin)
            {
                return "Python的插件,作者名为:Joker";
            }
    
            protected override string GetVersion(Plugin plugin)
            {
                return "Python的插件,版本号为:V---很奇怪----";
            }
        }

      好了,如何使用?我将新建一个类,把这些读取器包装起来,并且形成一条链,提供一个统一的接口给用户代码调用,下面看我如何包装的。

        ComponentAnalyzeclass ComponentAnalyzer:IPluginAnalyzerable    {

    private ComponentAnalyzer()
            {
                rootAnalyzer = new DotNetPluginAnalyzer();
                PythonPluginAnalyzer pythonAnalyzer = new PythonPluginAnalyzer();
                rootAnalyzer.NextAnalyzer = pythonAnalyzer;
            }
            #region 单例模式实现
         private ComponentAnalyzer()
         {

         } public static ComponentAnalyzer GetInstance() { return SingleHelper.GetInstance(); } private class SingleHelper { private static ComponentAnalyzer me = new ComponentAnalyzer(); public static ComponentAnalyzer GetInstance() { return me; } } #endregion PluginAnalyzer rootAnalyzer; public void Analyze(Plugin plugin) { rootAnalyzer.Analyze(plugin); } }

      很简单的一个类,我们先看构造函数:把所有语言的读取器连接起来,然后链头是rootAnalyzer,我们每次调用Analyze方法都会调用rootAnalyzer对应的方法,让其在内部传递。弄到这里,差不多完成了,大家可以在最下面直接下载源码运行看结果,下面给出客户端测试类。

    class Programe
        {
            public static void Main(string[] args)
            {
                IPluginAnalyzerable dotnetAnalyzer=ComponentAnalyzer.GetInstance();
                Console.WriteLine("输入Q退出");
                while(true)
                {
                    Plugin plugin = RandomPlugin();
                    dotnetAnalyzer.Analyze(plugin);
                    if (Console.ReadLine().ToUpper() == "Q")
                    {
                        break;
                    }
                }
            }
            private static Plugin RandomPlugin()
            {
                Random random = new Random();
                PluginType type = (PluginType)random.Next(0, 2);
                String plaginPath = Path.GetRandomFileName();
                Plugin result = new Plugin(type, plaginPath);
                return result;
            }
        }
    View Code

        测试结果:看,以一致的方式执行,但是会得到不一样的效果,责任被推到合适的地方做出相应的处理。

      到这里有人会说,那如何证明该模型的扩展性?? 好,下面我扩展一种语言读取器,看我改了多少,对系统影响了多少?

    扩展性测试

       我以Ruby为例。

        1.在PluginType中添加一个枚举内容Ruby:

        2.添加一个Ruby读取器:

        3.在ComponentAnalyzer(前面说的包装器)中,把该读取器添加到链条上!

        

        为了测试,在客户端代码中修改Random随机生成数,使其能生成3,大功告成!(这是测试相关,我们没有修改实际客户端任何代码)

         顺利扩展!!!我们修改的只是上层的代码,对于底层,也提供了扩展点,符合对修改封闭,对扩展开放。

    总结

      完成了,大家也累了,希望有不对的地方大家大力拍,面向组合编程,面向接口编程,不要面向具体实现类编程,这是我学习设计模式感受最深的一句话。谢谢大家观看。下面提供完整源码。

                                       完整Demo下载

  • 相关阅读:
    Django框架(二)
    USACO 2019 December Contest 随记
    Codeforces 1249E By Elevator or Stairs? 题解
    NIKKEI Programming Contest 2019-2 D 部分分题解
    Codeforces 1196D2 RGB Substring (Hard version) 题解
    HDU5943 Kingdom of Obsession 题解
    智能账单统计软件开发日志3 图像比对算法
    Codeforces #536 A..D 题解
    智能账单统计软件开发日志2 图像形态优化
    智能账单统计软件开发日志1 立项与环境配置
  • 原文地址:https://www.cnblogs.com/Jarvin/p/3750647.html
Copyright © 2011-2022 走看看