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 ...
随机推荐
- git学习(五):克隆和推送远程仓库
这里我已经注册好了GitHub账号了 生成本地的ssh和在github上添加ssh 在本地 ssh-keygen -t rsa -C "carryhjr@gmail.com" 一路 ...
- eclipse项目上面有个红叉,但是没有任何地方有错误
eclipse项目上面有个红叉,但是没有任何地方有错误,clear,refresh,重启都试过了,依然没用, 后来我换了一个workspace,编译的时候提示: Description Resourc ...
- CollectionView水平和竖直瀑布流的实现
最近在项目中需要实现一个水平的瀑布流(即每个Cell的高度是固定的,但是长度是不固定的),因为需要重写系统 UICollectionViewLayout中的一些方法通过计算去实现手动布局,所以本着代码 ...
- JS - 柯里化
一:what's this? 柯里化: 是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数而且返回结果的新函数的技术.其实,柯里化就是用闭包原理实现函数 ...
- BZOJ 4066 简单题 ——KD-Tree套替罪羊树
[题目分析] 直接x,y二维轮番划分,暴力即可. 套上替罪羊,打碎重构,对于时间复杂度有了保证. 写起来好麻烦,重构的技巧很棒! [代码] #include <cstdio> #inclu ...
- 0421 & SX2016
山西省选...这个省...不算强吧...然而就是这么腊鸡题目还是wa得一无是处...怎么办啊怎么办啊...无处拯救青春和未来啊... T1: POI2004原题 BZOJ1524 n<=16.这 ...
- 【BZOJ3156】防御准备 斜率优化DP
裸题,注意:基本的判断(求Min还是Max),因为是顺着做的,且最后一个a[i]一定要取到,所以是f[n]. DP:f[i]=min(f[j]+(i-j-1)*(i-j)/2+a[i]) 依旧设x&g ...
- Unity3d:UI面板管理整合进ToLua
本文基于 https://github.com/chiuan/TTUIFramework https://github.com/jarjin/LuaFramework_UGUI 进行的二次开发,Tha ...
- 整理ViewController的生命周期和加载过程
按照执行顺序排列 - initWithCoder:通过nib文件初始化时触发 - awakeFromNib:nib文件被加载的时候,会发送一个awakeFromNib的消息到nib文件中的每个对象 p ...
- 如何让{dede:channel}有子栏目显示子栏目,无子栏目不显示同级栏目
我们在使用织梦系统制作网站时经常会遇到网站栏目较多,显示当前栏目下的二级与三级栏目时,使用栏目嵌套标签,但是当三级栏目为空时,会显示同级栏目.从用户体验角度出发,常理情况下也是需要空白的,即二级栏目下 ...