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 ...
随机推荐
- 18.tty驱动程序框架
tty驱动程序框架 一.TTY概念解析 在Linux系统中,终端是一类字符型设备,它包括多种类型,通常使用tty来简称各种类型的终端设备. 1.1串口终端(/dev/ttyS*) 串口终端是使用计算机 ...
- PostSharp 4.0注册机实现过程
PostSharp是基于.NET平台设计的比较强调易学易用的AOP框架. 什么是AOP? http://wayfarer.cnblogs.com/articles/241024.html 新版的已失效 ...
- racket
let 和 let* 区别 ``` racket // 这是对的 (let* ([x (random 4)][o (random 4)] [diff (number->string (abs ( ...
- jQuery页面加载初始化的3种方法
jQuery 页面加载初始化的方法有3种 ,页面在加载的时候都会执行脚本,应该没什么区别,主要看习惯吧,本人觉得第二种方法最好,比较简洁. 第一种: $(document).ready(functio ...
- 总结js的一些复制方法
1.复制对象: var item1={XXX}; var item2=$.extend(true,{},item1);//深度克隆对象(jQuery方法). lodash也有相关方法:https:// ...
- SVG文件:从Illustrator导文件到Web
可缩放矢量图形(SVG)是早在1998年就已经有的一种矢量图像格式.它总是和Web一起发展,但是直到现在才开始赶上Web发展的步伐.如今我们已经不能否认SVG和Web的相关性,所以让我们来学习一下从I ...
- Unity3d:UI面板管理整合进ToLua
本文基于 https://github.com/chiuan/TTUIFramework https://github.com/jarjin/LuaFramework_UGUI 进行的二次开发,Tha ...
- sort命令
1.默认情况下,sort命令,以字母序进行文本排序sort word.txt2.如果想对数字进行排序,可以使用-n参数sort num.txt -n3指定列排序下面是对passwd文件,以冒号(:)进 ...
- hdu 2037简单贪心--活动安排问题
活动安排问题就是要在所给的活动集合中选出最大的相容活动子集合,是可以用贪心算法有效求解的很好例子.该问题要求高效地安排一系列争用某一公共资源的活动.贪心算法提供了一个简单.漂亮的方法使得尽可能多的活动 ...
- [ios]利用alertView 插入数据都数据库。笔记
利用alertView 插入数据都数据库 -(void)addItemToList { UIAlertView *alter=[[UIAlertViewalloc]initWithTitle:@&qu ...