C#编程模式之扩展命令
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#编程模式之扩展命令的更多相关文章
- ASP.NET Core 6框架揭秘实例演示[10]:Options基本编程模式
依赖注入使我们可以将依赖的功能定义成服务,最终以一种松耦合的形式注入消费该功能的组件或者服务中.除了可以采用依赖注入的形式消费承载某种功能的服务,还可以采用相同的方式消费承载配置数据的Options对 ...
- Scalaz(54)- scalaz-stream: 函数式多线程编程模式-Free Streaming Programming Model
长久以来,函数式编程模式都被认为是一种学术研究用或教学实验用的编程模式.直到近几年由于大数据和多核CPU的兴起造成了函数式编程模式在一些实际大型应用中的出现,这才逐渐改变了人们对函数式编程无用论的观点 ...
- 泛函编程(27)-泛函编程模式-Monad Transformer
经过了一段时间的学习,我们了解了一系列泛函数据类型.我们知道,在所有编程语言中,数据类型是支持软件编程的基础.同样,泛函数据类型Foldable,Monoid,Functor,Applicative, ...
- MXNet设计笔记之:深度学习的编程模式比较
市面上流行着各式各样的深度学习库,它们风格各异.那么这些函数库的风格在系统优化和用户体验方面又有哪些优势和缺陷呢?本文旨在于比较它们在编程模式方面的差异,讨论这些模式的基本优劣势,以及我们从中可以学到 ...
- WinDbg 命令三部曲:(二)WinDbg SOS 扩展命令手册
本文为 Dennis Gao 原创技术文章,发表于博客园博客,未经作者本人允许禁止任何形式的转载. 系列博文 <WinDbg 命令三部曲:(一)WinDbg 命令手册> <WinDb ...
- 为了支持AOP的编程模式,我为.NET Core写了一个轻量级的Interception框架[开源]
ASP.NET Core具有一个以ServiceCollection和ServiceProvider为核心的依赖注入框架,虽然这只是一个很轻量级的框架,但是在大部分情况下能够满足我们的需要.不过我觉得 ...
- (ZZ)WPF经典编程模式-MVVM示例讲解
http://www.cnblogs.com/xjxz/archive/2012/11/14/WPF.html 本篇从两个方面来讨论MVVM模式: MVVM理论知识 MVVM示例讲解 一,MVVM理论 ...
- 《JAVA与模式》之命令模式
在阎宏博士的<JAVA与模式>一书中开头是这样描述命令(Command)模式的: 命令模式属于对象的行为模式.命令模式又称为行动(Action)模式或交易(Transaction)模式. ...
- iOS 网络编程模式总结
IOS 可以采用三类api 接口进行网络编程,根据抽象层次从低到高分别为socket方式.stream方式.url 方式. 一 .socket 方式 IOS 提供的socket 方式的网络编程接口为C ...
随机推荐
- hash表及Java中的HashMap与HashSet
链接: http://alex09.iteye.com/blog/539545/ 当程序试图将一个 key-value 对放入 HashMap 中时,程序首先根据该 key 的 hashCode() ...
- ASP.Net Core 里是如何把一个普通的 Action 返回类型转换为某种 IActionResult 的
秘密在于这个类型: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker 在它的 CreateActionResult 方法里会将相关类型 ...
- 学习微信小程序之css9内边距
padding内边距 <!DOCTYPE html> <html lang="en"> <head> <meta charset=&quo ...
- Web.xml配置参数详解
1 定义头和根元素 部署描述符文件就像所有XML文件一样,必须以一个XML头开始.这个头声明可以使用的XML版本并给出文件的字符编码.DOCYTPE声明必须立即出现在此头之后.这个声明告诉服务器适用的 ...
- (转) JAVA中如何设置图片(图标)自适应Jlable等组件的大小
一.问题: 一个程序,组件上设置某个图片作为图标,因为的label(应该说是组件)已经设定了固定大小, 所以再打开一些大图片时,超过组件大小的部分没显示出来,而小图片又没填充完整个组件 二.解决这个问 ...
- json相关,浏览器打开json格式的api接口时,进行格式化,chrome插件
在chrome浏览器中安装Google jsonview插件能够自动格式化json格式的数据.
- 《DSP using MATLAB》示例Example5.23
代码: conv_time = zeros(1,150); fft_time = zeros(1, 150); % % Nmax = 2048; for L = 1:150 tc = 0; tf = ...
- hdu3549还是网络流
最后一次训练模板(比较熟练了) 接下来训练网络流的建图 #include <cstdio> #define INF 2147483647 int n,m,ans,x,y,z,M,h,t,T ...
- 【模拟】POJ 3087
直达–>POJ 3087 Shuffle'm Up 题意:一开始没怎么看明白,注意现是从S2里拿牌放在最底下,再放S1,这样交叉放(我一开始以为是S1和S2随意哪个先放,分别模拟取最小),然后在 ...
- IE11 上的3个bug
1.IE 11在popstate上无法正常使用,所以,需要使用老方法hashchange.有一个叫History.js的library,是可以解决这个问题.但如果url在"#"后跟 ...