也许你看过第一篇,也许没有,如果没有我推荐你看了继续看这个,因为这是接在那个下面的。这里将对上一篇进行完善,实现一个设想中他该那么工作的一组类。来看代码吧……
//CMDManager.cs

/**//// <summary>
/// 这里叫他命令管理器
/// 用于对命令对象的管理和传递
/// 设计之美——命令模式(二)
/// 也许你看过第一篇,也许没有,如果没有我推荐你看了继续看这个,因为这是接在那个下面的。
/// 上一篇实现了一些乱七八糟的demo 我是这么觉得,很显然我不满意这样的结果
/// 我希望以一个更简单的方式来实现我的要求,我希望我只要通过一个属性设置所有可支持的命令
/// 比如上一demo中 启动命令
/// 在上面增加一个属性[CmdAcctib("启动")]
/// 然后我们需要一个关于启动的命令
/// 嗯 当初空余的属性对象看起来用得到了
/// 我们得需要一些东西来告诉外部的对象如何进行命令执行
///
/// 新 Demo 中我们仅对无参数的方法和公开属性进行操作
/// 是觉得有限制么?嗯? 你觉得发射有什么做不到的么?没有!是的没有!
///
/// 好吧我们先来设计关于一个简单的反射
///
/// 请去往CmdConfig.cs->(希望你还记得我的文章怎么看:)
///
/// ->包装器
/// 终于快完成了 意味着你不用再跳任何一次了!
/// 放心吧我保证!!
///
/// 来看看这个类的功能设计
/// </summary>
class CMDManager

...{

//需要一个清单来进行操作
//这里使用了一个字典

/**//// <summary>
/// 命令对象字典
/// </summary>
Dictionary<Type, List<ICmdObj>> _CmdObjDic;

ICmdObjFactory _CmdObjFactory;
static CMDManager _Instance;
//很显然这个类只会生成一次
//所以使用单件模式
public static CMDManager Instance

...{
get

...{
if (_Instance == null)

...{
_Instance = new CMDManager();
}
return CMDManager._Instance;
}

set ...{ CMDManager._Instance = value; }
}

private CMDManager()

...{
_Init();
}


//然后我们需要一个初始化函数
//这里需要做些什么呢?
//需要遍历一个程序集,并且生成可使用的对象和命令列表
void _Init()

...{
_CmdObjDic = new Dictionary<Type, List<ICmdObj>>();
_CmdObjFactory = new ClassCmdObjFactory();//这里使用类包装工厂

foreach (Type t in Assembly.GetExecutingAssembly().GetTypes())

...{
bool _isReceiver = false;
foreach (Type Inter in t.GetInterfaces())

...{
if (Inter == typeof(IReceiver))

...{
_isReceiver = true;
break;
}
}
if (!_isReceiver) continue;
//判断是否为接受者接口
//遍历属性 和 方法
List<ICmdObj> result = new List<ICmdObj>();

foreach (MemberInfo var in t.GetMembers())

...{
foreach (object attrib in var.GetCustomAttributes(true))

...{
if (attrib is CmdAttrib)

...{
result.Add(_CmdObjFactory.Creat(var, attrib as CmdAttrib));
}
}

}
//foreach (PropertyInfo var in t.GetProperties())
//{
// foreach (object attrib in var.GetCustomAttributes(true))
// {
// if (attrib is CmdAttrib)
// {
// result.Add(_CmdObjFactory.Creat(var, attrib as CmdAttrib));
// }
// }

//}

_CmdObjDic.Add(t, result);

//生产完毕
//接着干嘛?
//当然是调用咯!
//很显然我们不希望手动去写没一个命令 那么就让代码生成器给写一个把
//首先得看一下关于模板的设计
//不过如果带参数就比较麻烦了 T T
//跳往模板->
//(很抱歉 又让您跳了....:p

}



}

public ICmdObj GetCmd(IReceiver receiver, string cmdname)

...{
Type rtype = receiver.GetType();

if (_CmdObjDic.ContainsKey(rtype))

...{
foreach (ICmdObj var in _CmdObjDic[rtype])

...{
if (var.Name == cmdname)

...{
//这里将进行接收者的赋值 但是很显然一个问题就是无法进行 直接赋值的
//但是我们查找到的却相当于一个模板 重新制作一份命令
return _CmdObjFactory.Creat(var, receiver);
}
}
}

//查找基类是接收着的类
foreach (KeyValuePair<Type, List<ICmdObj>> var in _CmdObjDic)

...{
if (var.Value.Count > 0)

...{
if (var.Key.BaseType == rtype)

...{
foreach (ICmdObj cmdobj in var.Value)

...{
if (cmdobj.Name == cmdname)

...{
//这里将进行接收者的赋值 但是很显然一个问题就是无法进行 直接赋值的
//但是我们查找到的却相当于一个模板 重新制作一份命令

return _CmdObjFactory.Creat(cmdobj, Activator.CreateInstance(var.Key, receiver) as IReceiver);
}
}
}
}
}

throw new Exception("未找到有效的命令!");
}
//->模板
//先不管带参数的
//演示而已 嘿嘿 就让我偷回懒吧!
public class classname : CmdCilent

...{
//构造
public classname(IReceiver receiver)
: base(receiver)

...{
}

public void cmdname()

...{
SendCmd(new CmdMessage(CMDManager.Instance.GetCmd(this._Receiver, "cmdname")));
}
}


/**//// <summary>
/// 代码生成器
/// </summary>
/// <param name="name"></param>
public void CsFileCreat()

...{
string head = @"

class C{0} : CmdCilent
{
public C{0}(IReceiver receiver)
: base(receiver)
{
}

{1}
}

";
string body = @"
public void {0}()
{
SendCmd(new CmdMessage(CMDManager.Instance.GetCmd(this._Receiver, {1})));
}
";
StringBuilder sb = new StringBuilder();
sb.Append("namespace DS_CMD.Command{");
foreach (KeyValuePair<Type, List<ICmdObj>> var in _CmdObjDic)

...{
if (var.Value.Count > 0)

...{
StringBuilder sbody = new StringBuilder();
foreach (ICmdObj cmd in var.Value)

...{
sbody.Append(body.Replace("{1}", """ + cmd.Name + """).Replace("{0}",cmd.Name));
}
sb.Append(head.Replace("{0}", var.Key.Name).Replace("{1}", sbody.ToString()));
}
}
sb.Append("}");

System.IO.File.WriteAllText("mycmd.cs", sb.ToString(),System.Text.Encoding.Default);
}

//done!
//测试下
//运行一次 将在目录下生成一个mycmd.cs
//然后拷贝进项目 再 测试一下

}

/**//// <summary>
/// 命令类型
/// </summary>
//internal enum CmdType
//{
// 属性,
// 方法,
// 事件
//}

//->CmdConfig.cs
//这里我们将进行命令对象的配置工作
//我把CmdType 挪到了这里方便查看
//我尝试使用一种更灵活方便的配置来制造命令扩展类
//但是又不希望淹没在配置文件和一堆的Class中
//既然2种方法都不一定可取,那么就两种一起采用吧,使用哪一种按个人需求来判定
//那么这里就使用两种方式来生产命令对象
//第一种:
//通过一个上一个demo中的第一个类,扩展对象的类. 那样得到最高的访问权限 但是不得不进行一次类型转换 必须进行一次类型判断
//第二种
//通过 IReceiver 接口 获得更好的封装性 但是得使用反射达到目的,控制能力不是很强
//第三种
//通过万能的配置文件,获得最灵活的使用方式,但是很显然不得不在反射的基础上,还要进行复杂的配置
//
//选用哪一种都是无所谓的事情 就看个人爱好了
//前两种有区别的就是内部调用方式,但是这里封装的话 还是一样的,我称他为 InlineCmd
//后一种就是说的ConfigCmd了
//总结下,分析的流程
//控制对象<------命令1- - 包装 - ->命令纸条--- 控制器
// | |
// --<-------命令2- - 包装 - ->命令纸条---
//懒得画图 体谅下
//通过2种方式对对象进行命令封装 然后 把该命令包装成 命令纸条 然后交给控制器处理
//什么啊,比昨天的麻烦多了 不仅要做命令类 还有 命令纸条类
//嗯。。没错,但是你编码的时候却没有那么麻烦,纸条包装由我们的命令管理类进行处理了,而且对命令的编写你拥有3种方式自由选择。
//控制器那边使用一个清单生成器,进行自动清单生成。 这下可以让人满意了么。
//试想一下过程 我们 编写一个控制对象 和 几个命令 剩下的就交给系统处理了。很完美吧!
//那么我们来制作吧!
//首先我们把命令纸条写写
//跳往->CmdMessage.cs

//->继续配置
//欢迎你又回来了
//继续看上面的 纸条完成了 控制器有了? 从那边抓过来一个

//跳往万能控制器->

//->继续配置之二
//就少最后一个东西了包装器
//其实包装器有2个东西,一个就是自动包装的类
//还有就是包装完成的产品
//命令纸条就是包装完成的产品
//学会手动包饺子,自动的才知道怎么干的!
//这里该使用一个工厂进行配置了
//因为将有两种产品
//一种是基于类的命令配置
//一种是基于属性配置的那么如何生产呢
//跳往包装器->


//->万能控制器

/**//// <summary>
/// 万能控制器
/// </summary>
class CmdCilent : ICilent

...{
protected IReceiver _Receiver;

public CmdCilent(IReceiver receiver)

...{
_Receiver = receiver;
}


ICilent 成员#region ICilent 成员


/**//// <summary>
/// 这个先不管
/// </summary>
/// <param name="cmd"></param>
void ICilent.SendCmd(string cmd)

...{
throw new Exception("The method or operation is not implemented.");
}


/**//// <summary>
/// 和原来一样
/// </summary>
/// <param name="cmd"></param>
public void SendCmd(ICmd cmd)

...{
cmd.Execute();
}

//好了
#endregion
//跳往继续配置之二->
}


//->包装器
//首先是我们的产品 统一规格的 来看一下
//制造一个命令对象
//虚的
abstract class CmdObj : ICmdObj

...{


ICmdObj 成员#region ICmdObj 成员

protected string _Name;

/**//// <summary>
/// 名称
/// </summary>
public string Name

...{

get ...{ return _Name; }
}
protected IReceiver _Receiver;

/**//// <summary>
/// 接收对象
/// </summary>
public IReceiver Receiver

...{

get ...{ return _Receiver; }
}
protected object _ExecuteObject;


/**//// <summary>
/// 控制对象名称
/// </summary>
public object ExecuteObject

...{

get ...{ return _ExecuteObject; }
}
protected CmdType _CmdType;

/**//// <summary>
/// 类型
/// </summary>
public CmdType CmdType

...{

get ...{ return _CmdType; }
}


protected object[] _Args;

/**//// <summary>
/// 保留参数
/// </summary>
public object[] Args

...{

get ...{ return _Args; }
}

#endregion
}

//首先是类包装产品

class ClassCmdObj : CmdObj

...{

/**//// <summary>
/// 这次比较完整一些
/// </summary>
/// <param name="name">The name.</param>
/// <param name="receiver">The receiver.</param>
/// <param name="cmdType">Type of the CMD.</param>
/// <param name="args">The args.</param>
public ClassCmdObj(string name, IReceiver receiver, CmdType cmdType, object executeObject, params object[] args)

...{
_Name = name;
_Receiver = receiver;
_CmdType = cmdType;
_Args = args;
_ExecuteObject = executeObject;
}
}


/**//// <summary>
/// 工厂接口
/// </summary>
interface ICmdObjFactory

...{
ICmdObj Creat(object t, CmdAttrib arg );
ICmdObj Creat(ICmdObj tpl,IReceiver receiver);
}


/**//// <summary>
/// 虚工厂
/// </summary>
abstract class CmdObjFactory : ICmdObjFactory

...{
public abstract ICmdObj Creat(object t, CmdAttrib arg);
public ICmdObj Creat(ICmdObj tpl, IReceiver receiver)

...{
return new ClassCmdObj(tpl.Name, receiver, tpl.CmdType, tpl.ExecuteObject, tpl.Args);
}
}


/**//// <summary>
/// 类建造工厂
/// </summary>
class ClassCmdObjFactory : CmdObjFactory

...{
public override ICmdObj Creat(object t, CmdAttrib arg)

...{
string name = t.GetType().Name;
switch (name)

...{
case "RuntimeMethodInfo":
return new ClassCmdObj(arg.Cmd, null, CmdType.方法, t, arg.Args);
break;
case "RuntimePropertyInfo":
return new ClassCmdObj(arg.Cmd, null, CmdType.属性, t, arg.Args);
break;
}
throw new Exception("不支持的类型!");
}
}

//好了该开始我们的包装器了
//跳往CMDManager.cs 包装器->
//->CmdMessage.cs
using System.Reflection;






/**//// <summary>
/// 命令消息
/// </summary>
[Serializable]
internal class CmdMessage:ICmd

...{
ICmdObj _msg;

/**//// <summary>
/// 开始构造
/// 很显然需要一个对命令进行描述的对象
/// 当然不能用 object 了 来构造一个
/// </summary>
/// <param name="?">命令描述</param>
public CmdMessage(ICmdObj msg)

...{
_msg = msg;
}

//public string Name
//{
// get
// {
// return _msg.Name;
// }
//}


/**//// <summary>
/// 运行命令
/// </summary>
public void Execute()

...{
switch (_msg.CmdType)

...{
case CmdType.属性:
//无法是设置一个属性
//属性也比较简单的
if (_msg.ExecuteObject is PropertyInfo)

...{
if (_msg.Args!=null && _msg.Args.Length == 1)

...{
PropertyInfo finfo = _msg.ExecuteObject as PropertyInfo;
finfo.SetValue(_msg.Receiver, _msg.Args[0],null);
}
else

...{
throw new Exception("必须传入对属性的设置值!");
}
}
else

...{
throw new Exception("命令类型和运行对象不匹配!");
}
break;
case CmdType.方法:
//调用一个方法
//暂时就以这个为主吧,比较简单
//这里要修改下昨天设计的 ICmd.cs 这个借口了 因为我们使用外部包装 就没必要进行使用字符串名称了 直接使用成员对象了
if (_msg.ExecuteObject is MethodInfo)

...{
MethodInfo minfo = _msg.ExecuteObject as MethodInfo;
minfo.Invoke(_msg.Receiver, _msg.Args);
}
else

...{
throw new Exception("命令类型和运行对象不匹配!");
}
break;
case CmdType.事件:
//事件
break;

}
}
//通用纸条完成!
//跳往CmdConfig.cs 继续配置->
}

license#region license
// **************************************************
// Copyright (c) 2008 fengjian (icesun963@Gmail.com)
// All rights reserved.
// 无聊加个版权玩
// **************************************************
#endregion

using System;
using System.Collections.Generic;
using System.Text;

namespace DS_CMD.Command.Demo

...{

class M邮件群发 : IReceiver

...{
string _S发件数量;

[CmdAttrib("Set100", "启动发邮件", "100")]
public string S发件数量

...{

get ...{ return _S发件数量; }

set ...{ _S发件数量 = value; }
}

bool _已经启动;

public bool 已经启动

...{

get ...{ return _已经启动; }

set ...{ _已经启动 = value; }
}

}


class M启动命令 : M邮件群发

...{


/**//// <summary>
/// Initializes a new instance of the <see cref="M启动命令"/> class.
/// </summary>
/// <param name="_接受者">The _接受者.</param>
public M启动命令(IReceiver _接受者)

...{
_R接受者 = _接受者 as M邮件群发;
}


[CmdAttrib("Start", "启动发邮件")]
public void S启动()

...{
_R接受者.已经启动 = true;
Console.WriteLine("对象已经启动...");
}

M邮件群发 _R接受者;



/**//// <summary>
/// 运行命令
/// </summary>
public void Execute()

...{
S启动();
}
}



}


static void Main(string[] args)

...{
//DS_CMD.Command.Demo._入口._Main一号();
//DS_CMD.Command.Demo._入口._Main二号();
//DS_CMD.Command.Demo._入口._Main三号();
DS_CMD.Command.Demo.M邮件群发 s = new DS_CMD.Command.Demo.M邮件群发();
Command.CMDManager.Instance.CsFileCreat();
//运行第一次
Console.WriteLine("检查状态 >> {0}", s.S发件数量);
CM邮件群发 c = new CM邮件群发(s);
c.Set100();
Console.WriteLine("检查状态 >> {0}", s.S发件数量);
Console.WriteLine("检查状态 >> {0}", s.已经启动);
CM启动命令 cs = new CM启动命令(s);
cs.Start();
Console.WriteLine("检查状态 >> {0}", s.已经启动);

Console.ReadKey();
}
贴完了,希望大家喜欢 :)