C#编程模式之扩展命令

前言

根据上一篇的命令模式和在工作中遇到的一些实际情况,有了本篇文章,时时都是学习的一个过程,会在这个过程中发现许多好的模式或者是一种开发方式,今天写出来的就是我工作中常用到的,自己感觉这种方式很优雅很漂亮,就自己试着实现了一下,可能原框架中不是这样的,有许多不足之处还请大家指点。

需求

我还不清楚这种方式是模式还是框架开发中用到的技术,我暂且叫它为命令控制器吧。

命令控制器的主要功能就是获取用户提供的命令,然后来执行命令。 在这里我把要执行的“命令”设计成一个函数,会对应着一个String类型的命令字符串,并且命令控制器是允许扩展的。

实现
首先我定义了一个属性类,用于在扩展的命令类、或者命令函数上,只有一个CommandName属性,作用于命令函数上的话,则代表命令名称,如果是作用于类上面的话就代表命令类别的名称,只是考虑可以作为一个分类,这部分在后面有讲到,可以自定义实现。

     /// <summary>
/// 命令所用代码属性类
/// </summary>
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
public class CommandAttribute : Attribute
{
private string commandName = null; public string CommandName
{
get { return commandName; }
set { commandName = value; }
} public CommandAttribute(string CommandName)
{
commandName = CommandName;
}
}

有了这个属性类了,我们就要把它用起来,定义一些后面要用到的命令示例类,

     /// <summary>
/// 示例:命令类以及命令函数,亦可当作为扩展
/// </summary>
[Command("Test")]
public class CommandTest : CommandMethod
{
[Command("MyCommandone")]
public object test(ICommandParameter commandparameter)
{
return null;
} [Command("MyCommandone1")]
public object test1(ICommandParameter commandparameter)
{
return null;
} [Command("MyCommandone2")]
public object test2(ICommandParameter commandparameter)
{
return null;
} [Command("MyCommandone3")]
public object test3(ICommandParameter commandparameter)
{
return null;
} [Command("MyCommandone4")]
public object test4(ICommandParameter commandparameter)
{
return null;
}
}

上面的示例代码中可以看到CommandTest类继承自CommandMethod类,而类里面的一些函数的签名也是一样的,函数参数都为ICommandParameter接口类型,这就是扩展命令方法时要遵循的一些规范,定义的规范:

     /// <summary>
/// 扩展命令函数的参数规范
/// </summary>
public interface ICommandParameter
{ } /// <summary>
/// 扩展命令方法类基类
/// </summary>
public class CommandMethod
{ }

需要实现什么都是可以自定义,比如说可以在ICommandParameter接口中定义个object类型的名称为ContainerObject的属性,意思就是容器属性,可以在后面调用命令时,传入实例参数时设置容器属性的值,可以设置为任何你想设置的值到里面,然后再在命令函数里使用它,也可以根据抽象定义实现一个参数上下文对象专门用于处理扩展命令的,看需要自定义吧。

然后就是书写一个命令控制器的代码了,它呢主要负责把客户端注册进来的类型做一些处理,比如说 判断类型、反射类型获取函数命令以及函数信息、把命令函数转换成委托、维护命令列表等等一些简单的功能,还用到了一个CommandMethodActionDelegate类型的委托:

     public delegate object CommandMethodActionDelegate(ICommandParameter commandParameter);

     public class CommandController
{
private static CommandController _Instance = null; public static CommandController Instance
{
get
{
if (_Instance == null)
{
_Instance = new CommandController(HostDevelopment.Instance);
}
return _Instance;
}
} private HostDevelopment _CommandDevelopment = HostDevelopment.Instance; public CommandController(HostDevelopment commandDevelopment)
{
_CommandDevelopment = commandDevelopment;
} private Dictionary<string, CommandMethodActionDelegate> commandlist = new Dictionary<string, CommandMethodActionDelegate>(); private List<string> _commandNames = null;
/// <summary>
/// 命令名称集合
/// </summary>
public List<string> CommandNames
{
get
{
if (_commandNames == null)
{
GetCommandNames();
}
return _commandNames;
}
} private void GetCommandNames()
{ if (commandlist.Count > )
{
if (_commandNames == null)
{
_commandNames = new List<string>();
}
foreach (string name in commandlist.Keys)
{
_commandNames.Add(name);
}
}
} public bool RegisterCommand(object instance)
{
Type t = instance.GetType();
CommandAttribute cmdatt = (CommandAttribute)Attribute.GetCustomAttribute(t, typeof(CommandAttribute), false);
if (cmdatt != null)
{
AddCommandToModel(instance);
return true;
}
else { return false; }
} private void AddCommandToModel(object instance)
{
Type t = instance.GetType();
MethodInfo[] methods = t.GetMethods();
foreach (MethodInfo methodinfo in methods)
{
CommandAttribute cmdatt = (CommandAttribute)Attribute.GetCustomAttribute(methodinfo, typeof(CommandAttribute), false);
if (cmdatt != null)
{ CommandMethodActionDelegate commanddelegate = (CommandMethodActionDelegate)Delegate.CreateDelegate(typeof(CommandMethodActionDelegate), instance, methodinfo.Name);
commandlist.Add(cmdatt.CommandName, commanddelegate);
} }
} internal object Execute(string commandName, ICommandParameter commandParameter)
{
if (commandName == null)
{
throw new ArgumentNullException("commandName");
}
if (!commandlist.ContainsKey(commandName))
{
return new ArgumentNullException("不包含的命令,命令无效");
}
CommandMethodActionDelegate cmdaction = commandlist[commandName];
return cmdaction.Invoke(commandParameter);
}
}

在CommandController类型中,RegisterCommand()方法为注册扩展命令到命令控制器,示例中的注册方式为手动的传入类型实例来注册的,也可以把实现方式修改为在命令控制器启动的时候获取当前系统所有依赖项的程序集,获取到所有符合类型规范的扩展命令类型,并且注册到控制器中。

上面代码中有说到的HostDevelopment类型,是我定义的一个宿主容器对象,用它来承载命令控制器,以及在这个系列的文章中,都是使用HostDevelopment来进行对控制器的承载,这是后话。现在来看一下HostDevelopment暂时的定义:

     public class HostDevelopment
{
private static HostDevelopment _commandDevelopment = null; public static HostDevelopment Instance
{
get
{
if (_commandDevelopment == null)
{
_commandDevelopment = new HostDevelopment();
}
return _commandDevelopment;
}
} private static ServiceContainer _serviceContainer = new ServiceContainer(); private void SetServiceContainer(Type t,object instance)
{
if (instance == null)
{
throw new ArgumentNullException("instance");
}
_serviceContainer.AddService(t, instance);
} private object GetServiceContainer(Type t)
{
return _serviceContainer.GetService(t);
} public CommandController CommandController
{
get
{
return (CommandController)GetServiceContainer(typeof(CommandController));
}
} public void Start()
{
SetServiceContainer(typeof(CommandController), new CommandController(this));
} public object Execute(string commandName, ICommandParameter commandParameter)
{
return CommandController.Execute(commandName, commandParameter);
}
}

看了这些了,应该就大致的明白了,不过现在这样的代码还是测试不了的,因为缺少一些实体。定义一个默认实现的命令参数规范:

     public class CommandParameterCase:ICommandParameter
{
private string _StrText; public string StrText
{
get { return _StrText; }
set { _StrText = value; }
}
}

然后再修改一下CommandTest类型中的第一个叫test的函数(对应的命令名称为MyCommandone),函数名称有点随意,大家不要介意这些。

         [Command("MyCommandone")]
public object test(ICommandParameter commandparameter)
{
if (commandparameter != null)
{
CommandParameterCase commandparametercase = commandparameter as CommandParameterCase;
return commandparametercase.StrText;
}
else { return null; }
}

这样所需的都定义齐了。
我们再看一下调用代码:

 HostDevelopment.Instance.Start();
HostDevelopment.Instance.CommandController.RegisterCommand(new CommandTest());
var strtext = HostDevelopment.Instance.Execute("MyCommandone", new CommandParameterCase() { StrText = "test" });

对了随便是打个断点或者是输出strtext都可以看到它的值。这里不作多的解释了。

最后加上对象关系图解吧,并不是什么标准的画法,有助于理解就行了。

END

作者:金源

出处:http://www.cnblogs.com/jin-yuan/

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

C#编程模式之扩展命令的更多相关文章

  1. ASP.NET Core 6框架揭秘实例演示[10]:Options基本编程模式

    依赖注入使我们可以将依赖的功能定义成服务,最终以一种松耦合的形式注入消费该功能的组件或者服务中.除了可以采用依赖注入的形式消费承载某种功能的服务,还可以采用相同的方式消费承载配置数据的Options对 ...

  2. Scalaz(54)- scalaz-stream: 函数式多线程编程模式-Free Streaming Programming Model

    长久以来,函数式编程模式都被认为是一种学术研究用或教学实验用的编程模式.直到近几年由于大数据和多核CPU的兴起造成了函数式编程模式在一些实际大型应用中的出现,这才逐渐改变了人们对函数式编程无用论的观点 ...

  3. 泛函编程(27)-泛函编程模式-Monad Transformer

    经过了一段时间的学习,我们了解了一系列泛函数据类型.我们知道,在所有编程语言中,数据类型是支持软件编程的基础.同样,泛函数据类型Foldable,Monoid,Functor,Applicative, ...

  4. MXNet设计笔记之:深度学习的编程模式比较

    市面上流行着各式各样的深度学习库,它们风格各异.那么这些函数库的风格在系统优化和用户体验方面又有哪些优势和缺陷呢?本文旨在于比较它们在编程模式方面的差异,讨论这些模式的基本优劣势,以及我们从中可以学到 ...

  5. WinDbg 命令三部曲:(二)WinDbg SOS 扩展命令手册

    本文为 Dennis Gao 原创技术文章,发表于博客园博客,未经作者本人允许禁止任何形式的转载. 系列博文 <WinDbg 命令三部曲:(一)WinDbg 命令手册> <WinDb ...

  6. 为了支持AOP的编程模式,我为.NET Core写了一个轻量级的Interception框架[开源]

    ASP.NET Core具有一个以ServiceCollection和ServiceProvider为核心的依赖注入框架,虽然这只是一个很轻量级的框架,但是在大部分情况下能够满足我们的需要.不过我觉得 ...

  7. (ZZ)WPF经典编程模式-MVVM示例讲解

    http://www.cnblogs.com/xjxz/archive/2012/11/14/WPF.html 本篇从两个方面来讨论MVVM模式: MVVM理论知识 MVVM示例讲解 一,MVVM理论 ...

  8. 《JAVA与模式》之命令模式

    在阎宏博士的<JAVA与模式>一书中开头是这样描述命令(Command)模式的: 命令模式属于对象的行为模式.命令模式又称为行动(Action)模式或交易(Transaction)模式. ...

  9. iOS 网络编程模式总结

    IOS 可以采用三类api 接口进行网络编程,根据抽象层次从低到高分别为socket方式.stream方式.url 方式. 一 .socket 方式 IOS 提供的socket 方式的网络编程接口为C ...

随机推荐

  1. F#之旅6 - 简单AV推荐系统

    上回说到用F#来写爬虫,这只是F#学习第一阶段的第一步.最开始,就对第一阶段做了这样的安排: 1.爬虫爬取AV数据 2.数据处理和挖掘 3.数据可视化(使用ECharts) 4.推荐系统 第一步很快就 ...

  2. Sublime Text 3 快捷键

    选择类Ctrl+D 选中光标所占的文本,继续操作则会选中下一个相同的文本.Alt+F3 选中文本按下快捷键,即可一次性选择全部的相同文本进行同时编辑.举个栗子:快速选中并更改所有相同的变量名.函数名等 ...

  3. [NHibernate]第一个NHibernate的应用配置

    NHibernate是.Net平台下一个成熟的,开源的对象关系映射器(ORM).本文来介绍第一次使用NHibernate的时候的配置. 1.下载NHibernate.Nhibernate官网最新版本为 ...

  4. docker 1.8+之后ubuntu安装指定版本docker-engine

    这边记录ubuntu安装过程,首先是官网文档 If you haven’t already done so, log into your Ubuntu instance. Open a termina ...

  5. HashMap的内部实现机制,Hash是怎样实现的,什么时候ReHash

    1.HashMap的内部实现机制 HashMap是对数据结构中哈希表(Hash Table)的实现,Hash表又叫散列表.Hash表是根据关键码Key来访问其对应的值Value的数据结构,它通过一个映 ...

  6. homebrew update 出现Failure while executing: git pull --quiet origin refs/heads/master:refs/remotes/origin/master解决方案

    具体可以参考https://github.com/Homebrew/homebrew/issues/21002 cd /usr/local git status git reset --hard or ...

  7. WP8解析JSON格式(使用DataContractJsonSerializer类)(推荐)

    DataContractJsonSerializer是.NET自带的类,在解析JSON格式的时候使用起来方便快捷,至于生成方面由于暂时没用到就没去看了.使用需要引用System.Runtime.Ser ...

  8. SUBLIME 添加PHP控制台

    原文地址:http://www.libenfu.com/sublime-%E6%B7%BB%E5%8A%A0php%E6%8E%A7%E5%88%B6%E5%8F%B0/ 点击工具 > 编译系统 ...

  9. Ubuntu下Android Studio环境搭建

    1.JDK安装 a.准备 由于AS(Android Studio)不支持openjdk,需要另行下载oracle jdk,同时官网指出对于64位linux系统,为了能在其上运行32位程序,需要安装一些 ...

  10. System.Dynamic.ExpandoObject 类型的简单使用

    该类型可以实现的是动态添加属性和移除属性,有点类似 js 中对象的操作,非常灵活 static void Main(string[] args) { dynamic obj = new System. ...