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 ...
随机推荐
- Unity引擎下最快的Xml读取器:UnityRapidXml
近期发现无论是系统的System.Xml还是Mono.Xml,其实都有这样或者那样的问题,所以决定自己搞一个快一点的xml parse.以前在C++里用过rapidxml,这个确实是神一般的存在,速度 ...
- 解决scrollview和viewpager冲突
import android.content.Context; import android.util.AttributeSet; import android.view.MotionEvent; i ...
- Http、Https请求工具类
最近在做微信开发,使用http调用第三方服务API,有些是需要https协议,通过资料和自己编码,写了个支持http和https的工具类,经验证可用,现贴出来保留,也供需要的人使用(有不足的地方,也请 ...
- Unity 依赖注入之二
1. 构造子注入 1.1 构造子注入初级代码 container.RegisterType<IMyWork, MyWork>(new InjectionConstructor(new Bo ...
- selenium使用Xpath定位之完整篇
其中有一片文章提到了xpath元素定位,但是该文章中有些并不能适应一些特殊与个性化的场景.在文本中提供xpath元素的定位终极篇,你一定能在这里找到你需要的解决办法. 第一种方法: 通过绝对路径做定位 ...
- System.getProperty()方法大全
System.out.println("当前程序所在目录:" + System.getProperty("user.dir")); // 当前程序所在目录 Sy ...
- Mac锁屏
http://www.dbform.com/html/2006/192.html 应用程序-实用工具-钥匙锁-菜单栏中的钥匙串访问-偏好设置-选中“在菜单栏中显示钥匙串”
- 4.4 多线程进阶篇<下>(NSOperation)
本文并非最终版本,如有更新或更正会第一时间置顶,联系方式详见文末 如果觉得本文内容过长,请前往本人"简书" 本文源码 Demo 详见 Github https://github.c ...
- 解决Xcode真机测试时ineligible devices的问题
升级了Xcode到6.3,连接真机测试时,出现不能选择设备.如图: 设备系统版本是8.3的,Xcode连接其他低系统版本的设备做真机测试时就不会有这个问题. 有人说这是Xcode6.3的bug. 我的 ...
- ElasticSearch问题记录
1.Young GC导致集群master重新选举,一台server fail [2016-12-10 07:38:24,546][WARN ][transport ] [BFRD_1] Receive ...