命令模式

背景:有时候我们需要对方法进行封装,通过对这些封装的方法进行调用,我们可以很好的处理一些事情。比如,记录日志,或者重复使用这些封装实现撤销功能。

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

结构:

image

例子:这次我们将设计一个家电自动化遥控器的API

需求分析:

遥控器的图:image

1)、遥控器上具有七个可编程的插槽、七个开关按钮和一个整体撤销按钮。

2)、通过创建一组API,使插槽可以控制一个或一组家电装置,这些装置指电灯、电风扇、热水器等。

3)、插槽还可以控制未来可能出现的家电装置。

4)、整体撤销按钮具有撤销上一个命令的功能。

初步思考:

1)、我们将设计一系列类,这些类都具有ON()和Off()方法。

2)、当遥控器上的on或off开关被按下时,某些类的on或off方法被调用,进而控制家电装置,但这些被调用的类是可以被改变的(因为插槽上的东西可以改变)。

3)、当on或off开关被按下时,如果我们通过if--else语句加以选择判断,那么第三点需求我们将难以满足。

4)撤销功能如何实现,上一个按钮是什么?针对的是哪一个装置?

进一步思考:

这次设计中不变的是遥控器(或者说是遥控器的按钮),变化的是家电装置,例如第一排开关可以控制电灯,也可以控制电风扇,或者未来可能出现的家电。所以我们需要对遥控器和家电装置进行解耦。此时我们想到了命令模式:遥控器(或者说遥控器上的按钮)就是命令的请求者,家电装置就是命令的执行者,我们所要做的就是将命令的请求者和命令的执行者解耦。

具体的过程:

1)、客户创建命令。

2)、客户将命令的执行者封装进命令对象里。

3)、命令的请求者调用命令。

4)、命令的执行者执行命令。

下面我们实现只有一组开关按钮的遥控器,类图如下:

image

代码如下:

 1http://www.cnblogs.com/Images/OutliningIndicators/None.gifclass RemoteLodder
 2http://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif    {
 3http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif        static void Main(string[] args)
 4http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif        {
 5http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif            SimpleRemoteControl remoteControl = new SimpleRemoteControl();
 6http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif            Light light = new Light();
 7http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif            LightOnCommand lightOnCommand = new LightOnCommand(light);
 8http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif            remoteControl.SetCommand(lightOnCommand);
 9http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif            remoteControl.ButtonWasPressed();
10http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif            Console.ReadLine();
11http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif        }
12http://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockEnd.gif    }
13http://www.cnblogs.com/Images/OutliningIndicators/None.gif public class Light
14http://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif    {
15http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif        public void On()
16http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif        {
17http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif            Console.WriteLine("Light is on");
18http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif        }
19http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif
20http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif        public void Off()
21http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif        {
22http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif            Console.WriteLine("Light is off");
23http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif        }
24http://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockEnd.gif    }
25http://www.cnblogs.com/Images/OutliningIndicators/None.gifpublic class LightOnCommand : Command
26http://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif    {
27http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif        Light light;
28http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif
29http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif        public LightOnCommand(Light paramLight)
30http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif        {
31http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif            this.light = paramLight;
32http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif        }
33http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif
34http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif        public void Execute()
35http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif        {
36http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif            light.On();
37http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif        }
38http://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockEnd.gif    }
39http://www.cnblogs.com/Images/OutliningIndicators/None.gifpublic interface Command
40http://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif    {
41http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif         void Execute();
42http://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockEnd.gif    }
43http://www.cnblogs.com/Images/OutliningIndicators/None.gifpublic class SimpleRemoteControl
44http://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif    {
45http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif        Command slot;
46http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif
47http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif        public void SetCommand(Command paramCommand)
48http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif        {
49http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif            this.slot = paramCommand;
50http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif        }
51http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif
52http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif        public void ButtonWasPressed()
53http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif        {
54http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif            slot.Execute();
55http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif        }
56http://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockEnd.gif    }

 

注释:命令的请求者:SimpleRemoteControl
命令的执行者:Light
命令接口:Command
具体的命令:LightOnCommand 
客户(封装命令的):RemoteLodde 
我们的遥控器共有七个插槽,可以用数组来实现,这里不写了。撤销按钮的功能可以通过栈来实现(对Command进行入栈,出栈即可)。
补充:
1)NoCommand模式

代码:

1http://www.cnblogs.com/Images/OutliningIndicators/None.gifpublic class NoCommand : Command
2http://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif    {
3http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif        public void Execute()
4http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif        {
5http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif        }
6http://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockEnd.gif    }

用途:当你不想返回一个有意义的对象时,就可以用空对象。客户也可以将处理null的责任转移给空对象。举例来说,遥控器出厂时可以用NoCommand对象对他进行初始化。
2)、宏命令
代码:

 1http://www.cnblogs.com/Images/OutliningIndicators/None.gifpublic class MacroCommand:Command
 2http://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif    {
 3http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif        List<Command> commands;
 4http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif
 5http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif        public MacroCommand(List<Command> commands)
 6http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif        {
 7http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif            this.commands = commands;
 8http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif        }
 9http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif
10http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif        public void Execute()
11http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif        {
12http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif            foreach (Command command in commands)
13http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif            {
14http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif                command.Execute();
15http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif            }
16http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif        }
17http://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockEnd.gif    }

用途:可以请求一次,执行多个命令。例如,按下一个按钮,实现打开电灯、电风扇、电视等功能。
应用:
1)、队列请求

想象有一个工作队列;你在某一端添加命令,然后另一端则是线程。线程进行下面的动作:从队列中取出一个命令,调用他的execute()方法,等待这个命令完成,然后将此命令丢弃,再取出下一个命令...此时,工作队列类和进行计算的对象之间完全解耦。当时线程可能进行财务运算,下一刻可能读取网络数据。
2)、日志请求
这需要我们将所有的动作(命令)记录在日志中,并能在系统死机后,对这些命令对象重新加载,成批的依次调用这些对象的execute()方法,恢复到之前的状态。比方说,对于电子表格的应用,我们可能想要实现的错误恢复方式是将电子表格的操作记录在日志中,而不是每次电子表格一有变化就记录整个电子表格。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值