设计之美——命令模式

开篇,这里开了个blog 那么就要写点东西上去了,最进做了个东西需要一堆命令做脚本,但是实现不怎么满意,这里重新编写一下然后与大家分享,本来还有更多的废话的 :) 但是 优快云 的blog 貌似不怎么可靠,直接没掉了

5555555555555 好几百个字呢,培我字来!!!

好了,那些个也找不到心情写了,然后只好郁闷的直接上代码了,命令模式我也不多说了,大家就去看吧 。这里直接贴上代码了,首先是几个借口,然后是demo设计和实现过程,嘿嘿 看书的流程有点像调试,大家凑合着看。

有什么意见和建议欢迎直接提出。 第一次写那么长的东西 ,有点心虚的說 。

希望大家喜欢!

 

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

namespace DS_CMD.Command
{
    
/// <summary>
    
/// 命令接受者
    
/// *通常这里将是一个关于对象的描述
    
/// 比如一个电视机的描述
    
/// 接口只是告诉管理器这里是个有效的可以进行命令接受的对象
    
/// </summary>

    interface IReceiver
    
{

    }

}

 

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

namespace DS_CMD.Command
{
    
/// <summary>
    
/// 命令对象接口
    
/// </summary>

    interface ICmd
    
{
        
/// <summary>
        
/// 执行命令
        
/// </summary>

        void Execute();
    }

}

 

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

namespace DS_CMD.Command
{
    
/// <summary>
    
/// 请求客户端
    
/// </summary>

    interface ICilent
    
{
        
/// <summary>
        
/// 请求一个命令外部
        
/// </summary>
        
/// <param name="cmd"></param>

        void SendCmd(string cmd);

        
/// <summary>
        
/// 请求一个命令
        
/// </summary>
        
/// <param name="cmd"></param>

        void SendCmd(ICmd cmd);
    }

}

 

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

namespace DS_CMD.Command
{
    
/// <summary>
    
/// 代码注释类
    
/// </summary>

    [AttributeUsage(AttributeTargets.Event | AttributeTargets.Field | AttributeTargets.Property | AttributeTargets.Method, Inherited = false, AllowMultiple = false)]
    
public class CodeDescription : Attribute
    
{
        
public CodeDescription()
        
{
        }


        
public CodeDescription(string description)
        
{
            
this._Desc = description;
        }


        
private string _Desc;

        
/// <summary>
        
/// 命令说明帮助
        
/// </summary>

        public string Description
        
{
            
get
            
{
                
return this._Desc;
            }

        }

    }


    
/// <summary>
    
/// 可执行命令属性类
    
/// </summary>

    [AttributeUsage(AttributeTargets.Event | AttributeTargets.Field | AttributeTargets.Property | AttributeTargets.Method, Inherited = false, AllowMultiple = false)]
    
public class CmdAttrib : CodeDescription
    
{
        
public CmdAttrib()
        
{
        }


        
/// <summary>
        
/// Initializes a new instance of the <see cref="CmdAttrib"/> class.
        
/// </summary>
        
/// <param name="cmd">外部执行的命令.</param>
        
/// <param name="description">命令说明帮助.</param>

        public CmdAttrib(string cmd, string description)
            : 
base(description)
        
{
            
this._Cmd = cmd;
        }


        
object[] _Args;

        
/// <summary>
        
/// 也许需要一些参数 *保留
        
/// </summary>

        public object[] Args
        
{
            
get return _Args; }
            
set { _Args = value; }
        }


        
string _Cmd;

        
/// <summary>
        
/// 外部执行的命令
        
/// 如果为空则使用方法名称
        
/// </summary>

        public string Cmd
        
{
            
get
            
{
                
return _Cmd;
            }

        }


    }

}

 

license

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

namespace DS_CMD.Command.Demo
{
    
/// <summary>
    
/// 邮件群发器中的主要对象
    
/// 这里用我自己的项目作为说明
    
/// 并且根据个人的需要进行设计的
    
/// 忽然觉得也许中文编程写起来会更清晰一些 所有我来尝试一下 
    
/// 看清楚哦 不是伪代码
    
/// (带字母是为了更好的定位)
    
/// </summary>

    class M邮件群发 : IReceiver
    
{
        
string _S发件数量;

        
public string S发件数量
        
{
            
get return _S发件数量; }
            
set { _S发件数量 = value; }
        }


        
bool _已经启动;

        
public bool 已经启动
        
{
            
get return _已经启动; }
            
set { _已经启动 = value; }
        }

      
//请跳往命令对象->

    }


    
//->编写客户端
    
//刚才构造了关于命令对象和接收对象,并且提供了两种方式进行调用
    
//下面该构造一个发送者了
    
//刚发现如果是字母开头无法很好的进行联想
    
//如果是下划线就开始变得好多了
    
//如果格式有点问题 请见谅
    class _控制器:ICilent
    
{
        
//->控制器
        M邮件群发 _控制对象;

        
public _控制器(M邮件群发 控制对象)
        
{
            _控制对象 
= 控制对象;
        }


        
ICilent 成员
    }


    
//->万能控制器
    class _万能控制器 : ICilent
    
{
        
//->控制器
        protected IReceiver _控制对象;

        
public _万能控制器(IReceiver 控制对象)
        
{
            _控制对象 
= 控制对象;
        }


        
ICilent 成员
    }

    
//万能控制器就那么简单? 恩....没错...
    
//然后是需要一个带命令列表的控制器

    
class _邮件群发控制器 : _万能控制器
    
{

        
public _邮件群发控制器(IReceiver 控制对象)
            :
base(控制对象)
        
{

        }


        
public void 启动()
        
{

            SendCmd(
new DS_CMD.Command.Demo.Cmd._命令纸条(new CmdObj("启动", _控制对象)));
        }



        
public void 停止()
        
{
            SendCmd(
new DS_CMD.Command.Demo.Cmd._命令纸条(new CmdObj("停止", _控制对象)));
        }


        
//看起来是完成了
        
//测试一下
        
//跳往Main三号->
    }


    
//制造一个命令对象
    class CmdObj : DS_CMD.Command.Demo.Cmd._命令纸条.ICmdObj
    
{

        
/// <summary>
        
/// 简单的模拟下就好了
        
/// </summary>
        
/// <param name="name"></param>
        
/// <param name="receiver"></param>

        public CmdObj(string name, IReceiver receiver)
        
{
            _Name 
= name;
            _Receiver 
= receiver;
        }


        
ICmdObj 成员
    }


    
class _入口
    
{
        
//->Main一号
        
//很欣慰的看到你来到这里 嘿嘿 有点废话了
        
//来看函数
        public static void _Main一号()
        
{
            
//首先我们需要一个接受者
            M邮件群发 m邮件群发 = new M邮件群发();
            
//我们发送一个启动命令
            ICmd cmd = new DS_CMD.Command.Demo.Cmd.M启动命令(m邮件群发);//这里有个工厂的话会好很多的 觉得呢?
            cmd.Execute();
            
//检查状态
            Console.WriteLine("检查状态 >> {0}", m邮件群发.已经启动);
            
//然后发送一个关闭命令
            cmd = new DS_CMD.Command.Demo.Cmd.M停止命令(m邮件群发);
            cmd.Execute();
            Console.WriteLine(
"检查状态 >> {0}", m邮件群发.已经启动);

            Console.ReadKey();

            
//运行下 恩 很完美吧 已经成功完成了
            
//但是这不是我想要的继续返回
            
//你不觉得有点长么?
            
//经常看到某些人说 OOP 的编写者被一堆Class掩埋 我这么记得 都是原话也许并不是这样 
            
//但是有一件事情是真实的 我知道如果 这个东西要执行50条的命令的话 无论如何 都必须有 50个类 
            
//我不得不重复 拷贝  修改 这样的一个过程
            
            
//如果你觉得 无所谓直接
            
//跳往SendCmd->

            
//如果你觉得 我也这么想 我们继续来完善和处理下这样的一个问题
            
//程序员总是懒惰的 希望设计一个简单的方法来完成所有的命令 我也一样  不然我不会在那个软件中使用那样的一种方式了 .
            
//但是事情并不是万能的 ,总是有很多问题,记得刚看到的一句话 脚本才是王道,确实如此,我们要设计一个脚本么 ?
            
//那可是一个庞大的工作 ,我可不想被他累死 .
            
//那么如何解决呢 ?
            
//回过去看下命令执行方式
            
//接受者 -> 重新包装一个命令 -> 执行命令
            
//接受貌似 没办法了  执行 就那么一条还想改变什么么 ?恩  包装 ...
            
//有没有更好的包装方式 ?
            
//首先 设想一下 ,如果我们构造一个 命令控制器的话 把所有的命令包装起来 然后执行 ?
            
//尝试一下再说 
            
//跳往控制器->

        }


        
//->Main二号
        public static void _Main二号()
        
{
            
//这里实现起来就简单一些了
            
//首先我们同样需要一个接受者
            M邮件群发 m邮件群发 = new M邮件群发();
            
//但是我们使用一个控制器
            _控制器 c = new _控制器(m邮件群发);
            c.启动();
            Console.WriteLine(
"检查状态 >> {0}", m邮件群发.已经启动);
            c.停止();
            Console.WriteLine(
"检查状态 >> {0}", m邮件群发.已经启动);
            Console.ReadKey();
            
//跑一下
            
//跑的還不错 至少我们不需要再去记一堆的命令在哪里了
            
//而且知道了哪些是可执行的
            
//但是这个例子有个致命的缺陷就是 你无法更好的使用一些东西
            
//也就是說 比如我要控制另外的不是群发器 我需要控制 一个浏览器的话 这样就毫无意义 我们不得不重新编写这里的所有代码
            
//现在有2个问题摆在面前  1.如何更简洁的 对命令进行控制  2.如何增加代码的灵活性更通用
            
//分析下几个对象
            
//首先是控制器,如果我们做好一系列的命令 放置到面板中 你可以简单的调用,然后提供一个通用的入口 用于定制你的命令的话.
            
//但是如何实现呢 ? 分析过程 :
            
//*命令列表->保持更安全的执行 如果没有这个我们很可能在程序中敲错代码 导致一堆问题 这个 ,我们必须制作
            
//接受者
            
//*控制的对象 也是必须的 但是这个没有统一的访问方式和办法. 啊哈 ,嗯 既然不统一 我们就让他通过配置来解决吧,我想这个不是什么难事 .
            
//命令对象,真的需要那么多的类么 ?我可没有耐心不断的编写真的,我发誓 .
            
//但是他是怎么工作的呢 ?
            
//见过几个方式 修改一些属性 调用几个方法 好像还有见过调用事件的.
            
//能优化么 ? 反射如何 ?
            
//修改 ?没问题 ,方法? 同样不是难事 ,事件 一样处理了.
            
//效果会如何呢? 大家都知道 反射的性能实在不怎么样.到底如何写出来看看好了
            
//跳往 纸条 ->

        }


        
//->Main三号
        public static void _Main三号()
        
{
            
//这里实现起来就简单一些了
            
//首先我们同样需要一个接受者
            M邮件群发 m邮件群发 = new M邮件群发();
            
//但是我们使用一个控制器
            _邮件群发控制器 c = new _邮件群发控制器(m邮件群发);
            c.启动();
            Console.WriteLine(
"检查状态 >> {0}", m邮件群发.已经启动);
            c.停止();
            Console.WriteLine(
"检查状态 >> {0}", m邮件群发.已经启动);
            Console.ReadKey();
            
//忽~~ 总算告一段落了
            
//如果有人发现还有一些地方没有实现 比如 CMDManager
            
//本来这是准备先设计后写Demo的,结果不知不觉.
            
//坏毛病不少啊
            
//大家凑和的看吧
            
//欢迎有什么问题指出和给我留言.
            
//这里只是自己个人的一些看法和思考方式 
        }


    }

   
}

///->命另对象:
///下面是命令对象名字空间
/// 我通常会希望有这样的一种简单的方式对命令进行调用
/// 我得到一个有效的命令列表 或者是一堆有效的命令对象 从程序或者是控制台进行调用

namespace DS_CMD.Command.Demo.Cmd
{
    
/// <summary>
    
/// 通常是这么一个情况
    
/// 接受者是不可能拥有相同的属性的
    
/// 因此无法进行抽象
    
/// 而我们调用必须拥有一系列的对象
    
/// 所以这里对对象进行了继承以获取对象的访问权限
    
/// 但是并不进行除了命令对象外的任何操作,以保持对象的安全
    
/// 但是有致命的缺点  就是无法传递接口 只能传递对象
    
/// 当然我们也可以使用反射的方式
    
/// 
    
/// </summary>

    class M启动命令 :M邮件群发, ICmd
    
{

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

        public M启动命令(M邮件群发 _接受者)
        
{
            _R接受者 
= _接受者;
        }



        [CmdAttrib(
"启动""启动发邮件")]
        
private void S启动()
        
{
            _R接受者.已经启动 
= true;
            Console.WriteLine(
"对象已经启动...");
        }


        M邮件群发 _R接受者;


        
/// <summary>
        
/// 运行命令
        
/// </summary>

        public void Execute()
        
{
            S启动();
        }

    }


    
//这里完成了一个简单的命令对象 就如上面所说的 我们应该可以使用另外一种方式进行对象的访问
    
//如果但是为了访问对象我们不得不开放访问接口,这个方式和上面的相比,访问更安全,但是必须对原有的访问权限进行修改
    class M停止命令 :  ICmd
    
{

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

        public M停止命令(IReceiver _接受者)
        
{
            _R接受者 
= _接受者;
        }



        [CmdAttrib(
"停止""停止发邮件...")]
        
public void S停止()
        
{
            
//这里将使用反射进行通用属性和方法的调用
            
//需要做的就是在接受者那里进行对象提取和调用
            
//比如我们使用另外一个属性的方式进行限制
            
//然后调用过程方法 这里就不进行编写了
            
//这里仅仅强制转换并且进行简单的操作。
            if (_R接受者 is M邮件群发)
            
{
                (_R接受者 
as M邮件群发).已经启动 = false;
            }

            Console.WriteLine(
"对象已停止...");
        }


        IReceiver _R接受者;


        
/// <summary>
        
/// 运行命令
        
/// </summary>

        public void Execute()
        
{
            S停止();
        }

    }

    
//请重新返回上面继续
    
//跳往编写客户端->

    
//->纸条
    
//通常对于命令来说就是一个有意义的符号,并且需要一个可传递的过程
    
//所以我想到了纸条
    
//只要把要说的写进去,一切都不是问题
     class _命令纸条 : ICmd
    
{

        ICmdObj _纸条;
        
/// <summary>
        
/// 开始构造
        
/// 很显然需要一个对命令进行描述的对象
        
/// 当然不能用 object 了 来构造一个
        
/// </summary>
        
/// <param name="?">命令描述</param>

        public _命令纸条( ICmdObj 命令描述)
        
{
            _纸条 
= 命令描述;
        }




        
/// <summary>
        
/// 命令类型
        
/// </summary>

       internal  enum CmdType
        
{
            属性,
            方法,
            事件
        }


        
/// <summary>
        
/// 纸条接口
        
/// </summary>

         internal interface ICmdObj
        
{
            
/// <summary>
            
/// 名称
            
/// </summary>

            string Name get;}

            
/// <summary>
            
/// 接受对象
            
/// </summary>

            IReceiver Receiver{get;}

            
/// <summary>
            
/// 英文不好
            
/// 叫他运行对对象把
            
/// </summary>

            string ExecuteObject get; }

            
/// <summary>
            
/// 命令类型
            
/// </summary>

            CmdType CmdType get;}

            
/// <summary>
            
/// 参数
            
/// </summary>

            object[] Args get;}
        }




    


        
/// <summary>
        
/// 运行命令
        
/// </summary>

        public void Execute()
        
{
            Console.WriteLine(
"执行纸条..." + _纸条.Name);
           
//通过反射进行对属性之类的操作
            
//这里同样不编写了 直接强制转换进行模拟下
            switch (_纸条.Name)
            
{
                
case "启动":
                    
if (_纸条.Receiver is M邮件群发)
                    
{
                        (_纸条.Receiver 
as M邮件群发).已经启动 = true;
                    }

                    
break;
                
case "停止":
                    
if (_纸条.Receiver is M邮件群发)
                    
{
                        (_纸条.Receiver 
as M邮件群发).已经启动 = false;
                    }

                    
break;
             
            }

            
        }

         
//挖喔 .看起来完成了 
         
//继续构造一个万能控制器
         
//跳往->万能控制器
    }


}

Command模式:将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化;对请求排队或记录请求日志,以及支持可撤消的操作。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值