Head First 设计模式之命令模式CommandPattern.docx
《Head First 设计模式之命令模式CommandPattern.docx》由会员分享,可在线阅读,更多相关《Head First 设计模式之命令模式CommandPattern.docx(16页珍藏版)》请在冰豆网上搜索。
HeadFirst设计模式之命令模式CommandPattern
HeadFirst设计模式之命令模式(CommandPattern)
前言:
本章会将封装带入到一个全新的境界,把方法调用封装起来。
通过封装方法调用,把运算块包装成形。
调用此运算的对象不需要知道事情是如何进行的,只要知道如何使用包装形成的方法来完成它就ok了。
1现实场景应用
现在有一个遥控器,该遥控器有7个插槽需要编程,可以在每个插槽上放上不同的装置,然后用按钮控制它,这七个插槽具备各自的“开”“关”按钮,还有一个整体用的撤销按钮,会撤销最后一个按钮的动作。
1.1创建第一个命令对象
1.1.1定义命令接口
[csharp]viewplaincopy在CODE上查看代码片派生到我的代码片
publicinterfaceCommand
{
voidExecute();
}
1.1.2实现一个打开灯的命令
publicclassLight//电灯类
publicvoidOn()
System.Console.WriteLine("LightisOn!
");
publicvoidOff()
System.Console.WriteLine("LightisOff!
publicclassLightOnCommand:
Command//实现开灯命令
privateLightlight;
publicLightOnCommand(Lightlight)
this.light=light;
publicvoidExecute()
light.On();
1.1.3使用命令对象
publicclassLightControl
privateCommandsoft;
publicvoidSetCommand(Commandcmd)
soft=cmd;//设置命令对象
publicvoidButtonWasPressed()
soft.Execute();//调用命令对象的方法
1.1.4简单测试
LightControllightControl=newLightControl();//模拟命令的调用者
Lightlight=newLight();//创建一个电灯对象,作为命令的接收者
LightOnCommandlightOnCommand=newLightOnCommand(light);//创建一个命令,并将接受者传递给它
lightControl.SetCommand(lightOnCommand);//将命令传给调用者
lightControl.ButtonWasPressed();//模拟触发按钮
1.2实现遥控器
publicclassRemoteControl
Command[]onCommands;//定义打开的命令数组
Command[]offCommands;//定义关闭的命令数组
publicRemoteControl()
onCommands=newCommand[7];
offCommands=newCommand[7];
CommandnoCommand=newNoCommand();
for(inti=0;i<7;i++)
onCommands[i]=noCommand;//初始化命令数组(默认设置为无命令)
offCommands[i]=noCommand;
//将命令设置到对应的控制器
publicvoidSetCommand(intindex,CommandonCommand,CommandoffCommand)
onCommands[index]=onCommand;
offCommands[index]=offCommand;
//触发打开控制器
publicvoidOnButtonWasPressed(intindex)
onCommands[index].Execute();
//触发关闭控制器
publicvoidOffButtonWasPressed(intindex)
offCommands[index].Execute();
publicoverridestringToString()
StringBuilderstr=newStringBuilder();
str.Append("\n------RemoteControl------\n");
for(inti=0;i{str.Append("[solt"+i+"]"+onCommands[i].GetType().FullName+""+offCommands[i].GetType().FullName+"\n");}returnstr.ToString();}}1.3实现其他控制器[csharp]viewplaincopy在CODE上查看代码片派生到我的代码片//关闭电灯命令publicclassLightOffCommand:Command{privateLightlight;publicLightOffCommand(Lightlight){this.light=light;}publicvoidExecute(){light.Off();}publicvoidUndo(){light.On();}}//打开电扇命令publicclassCeilingFanOnCommand:Command{CeilingFanceilingFan;intpreSpeed;publicCeilingFanOnCommand(CeilingFanceilingFan){this.ceilingFan=ceilingFan;}publicvoidExecute(){ceilingFan.On();}publicvoidUndo(){ceilingFan.Off();}}//关闭电扇命令publicclassCeilingFanOffCommand:Command{CeilingFanceilingFan;publicCeilingFanOffCommand(CeilingFanceilingFan){this.ceilingFan=ceilingFan;}publicvoidExecute(){ceilingFan.Off();}publicvoidUndo(){ceilingFan.On();}}//打开车库门命令publicclassGarageDoorOnCommand:Command{GarageDoorgarageDoor;publicGarageDoorOnCommand(GarageDoorgarageDoor){this.garageDoor=garageDoor;}publicvoidExecute(){garageDoor.On();}publicvoidUndo(){garageDoor.Off();}}//关闭车库门命令publicclassGarageDoorOffCommand:Command{GarageDoorgarageDoor;publicGarageDoorOffCommand(GarageDoorgarageDoor){this.garageDoor=garageDoor;}publicvoidExecute(){garageDoor.Off();}publicvoidUndo(){garageDoor.On();}}//打开CD命令publicclassStereCDOnCommand:Command{StereCDstereCD;publicStereCDOnCommand(StereCDstereCD){this.stereCD=stereCD;}publicvoidExecute(){stereCD.On();}publicvoidUndo(){stereCD.Off();}}//关闭CD命令publicclassStereCDOffCommand:Command{StereCDstereCD;publicStereCDOffCommand(StereCDstereCD){this.stereCD=stereCD;}publicvoidExecute(){stereCD.Off();}publicvoidUndo(){stereCD.On();}}1.4简单测试[csharp]viewplaincopy在CODE上查看代码片派生到我的代码片RemoteControlremoteControl=newRemoteControl();CeilingFanceilingFan=newCeilingFan("LivingRoom");//创建电扇对象GarageDoorgarageDoor=newGarageDoor();//创建车库门对象StereCDstereCD=newStereCD();//创建CD对象Lightlight=newLight();//创建电灯对象LightOnCommandlightOnCommand=newLightOnCommand(light);//创建开灯命令LightOffCommandlightOffCommand=newLightOffCommand(light);//创建关灯命令CeilingFanOnCommandceilingFanOn=newCeilingFanOnCommand(ceilingFan);//创建开电扇命令CeilingFanOffCommandceilingFanOff=newCeilingFanOffCommand(ceilingFan);//创建关电扇命令GarageDoorOnCommandgarageDoorOn=newGarageDoorOnCommand(garageDoor);//创建打开电扇命令GarageDoorOffCommandgarageDoorOff=newGarageDoorOffCommand(garageDoor);//创建关闭电扇命令StereCDOnCommandstereCDOn=newStereCDOnCommand(stereCD);//创建打开CD命令StereCDOffCommandstereCDOff=newStereCDOffCommand(stereCD);//创建关闭CD命令remoteControl.SetCommand(0,lightOnCommand,lightOffCommand);//将电灯命令设置到对应的控制器上remoteControl.SetCommand(1,ceilingFanOn,ceilingFanOff);//将电灯命令设置到对应的控制器上remoteControl.SetCommand(2,garageDoorOn,garageDoorOff);//将车库门命令设置到对应的控制器上remoteControl.SetCommand(3,stereCDOn,stereCDOff);//将CD命令设置到对应的控制器上remoteControl.OnButtonWasPressed(0);remoteControl.OffButtonWasPressed(0);remoteControl.OnButtonWasPressed(1);remoteControl.OffButtonWasPressed(1);remoteControl.OnButtonWasPressed(2);remoteControl.OffButtonWasPressed(2);remoteControl.OnButtonWasPressed(3);remoteControl.OffButtonWasPressed(3);1.5实现撤销命令1.5.1修改命令接口,新增Undo()方法[csharp]viewplaincopy在CODE上查看代码片派生到我的代码片publicinterfaceCommand{voidExecute();voidUndo();//新增撤销方法}1.5.2修改命令,实现Undo方法[csharp]viewplaincopy在CODE上查看代码片派生到我的代码片publicssLightOnCommand:Command{privateLightlight;publicLightOnCommand(Lightlight){this.light=light;}publicvoidExecute(){light.On();}publicvoidUndo()//实现Undo方法{light.Off();}}其他类都依次修改1.5.3修改RemoteControl类,新增Command对象记录上一步操作[csharp]viewplaincopy在CODE上查看代码片派生到我的代码片publicclassRemoteControlWithUndo{Command[]onCommands;Command[]offCommands;CommandundoCommand;//创建Command对象用来记录上一步执行的命令publicRemoteControlWithUndo(){onCommands=newCommand[7];offCommands=newCommand[7];CommandnoCommand=newNoCommand();for(inti=0;i<7;i++){onCommands[i]=noCommand;offCommands[i]=noCommand;}undoCommand=noCommand;}……………..publicvoidOnButtonWasPressed(intindex){onCommands[index].Execute();undoCommand=onCommands[index];//记录打开命令}publicvoidOffButtonWasPressed(intindex){offCommands[index].Execute();undoCommand=offCommands[index];//记录关闭命令}publicvoidUndoButtonWasPressed()//执行撤销{undoCommand.Undo();}…………}1.6宏命令让遥控器具有Party模式,即一个按键能够同步调用多个命令,这就是所谓的宏命令。[csharp]viewplaincopy在CODE上查看代码片派生到我的代码片publicclassMacroCommand:Command{Command[]commands;//定义命令数组,用来接收传入的命令publicMacroCommand(Command[]commands){mands=commands;}publicvoidExecute()//批量处理多个命令(即初始化的时候传入的命令数组){for(inti=0;icommands[i].Execute();}publicvoidUndo(){for(inti=0;icommands[i].Undo();}}2定义命令模式命令模式将“请求”封装成对象,以便使用不同的请求、队列或者日志来参数化其他对象。命令模式也支持可撤销的操作。定义命令模式类图:3命令模式的更多用途3.1队列请求命令将运算块打包,然后将它传来传去,即使在命令对象创建许久之后,运算依然可以被调用,甚至可以在不同的线程中被调用,我们可以利用这样的特性衍生一下应用,比如:日常安排、线程池、工作队列等。工作队列类和进行计算的对象之间完全是解耦的。它们只要是实现命令模式的对象就可以放到队列里边,当线程可用时就调用此对象的Execute()方法。3.2日志请求某些应用需要我们将所有动作记录到日志中,并在系统死机之后,重新调用这些动作恢复到之前的状态,命令模式就能够支持这一点。有许多调用大型数据结构的动作应用无法再每次改变发生时被快速的存储,通过使用记录日志,我们可以将上次检查点之后的所有操作记录下来,如果系统出现状况,可以从检查点开始应用这些操作。对于更高级的应用而言,这些技巧可以被扩展应用到事务处理中,即一整群操作必须全部完成,或者没有进行任何操作。3总结l命令模式将发出请求的对象和执行请求的对象解耦。l被解耦的两者之间是通过命令对象进行沟通的,命令对象封装了接收者和一个或一组动作。l调用者通过调用命令对象的Execute()发出请求,会使得接收者的动作被调用。l调用者可以接收命令当做参数,甚至在运行时动态进行。l命令可以支持撤销,做法是实现一个undo()方法来回到Execute()被执行之前的状态。l宏命令是命令的一种简单的延伸,允许调用多个命令,宏方法也可以支持撤销。l命令也可以用来实现日志和事务系统。
str.Append("[solt"+i+"]"+onCommands[i].GetType().FullName+""+offCommands[i].GetType().FullName+"\n");
returnstr.ToString();
1.3实现其他控制器
//关闭电灯命令
publicclassLightOffCommand:
Command
publicLightOffCommand(Lightlight)
light.Off();
publicvoidUndo()
//打开电扇命令
publicclassCeilingFanOnCommand:
CeilingFanceilingFan;
intpreSpeed;
publicCeilingFanOnCommand(CeilingFanceilingFan)
this.ceilingFan=ceilingFan;
ceilingFan.On();
ceilingFan.Off();
//关闭电扇命令
publicclassCeilingFanOffCommand:
publicCeilingFanOffCommand(CeilingFanceilingFan)
//打开车库门命令
publicclassGarageDoorOnCommand:
GarageDoorgarageDoor;
publicGarageDoorOnCommand(GarageDoorgarageDoor)
this.garageDoor=garageDoor;
garageDoor.On();
garageDoor.Off();
//关闭车库门命令
publicclassGarageDoorOffCommand:
publicGarageDoorOffCommand(GarageDoorgarageDoor)
//打开CD命令
publicclassStereCDOnCommand:
StereCDstereCD;
publicStereCDOnCommand(StereCDstereCD)
this.stereCD=stereCD;
stereCD.On();
stereCD.Off();
//关闭CD命令
publicclassStereCDOffCommand:
publicStereCDOffCommand(StereCDstereCD)
1.4简单测试
RemoteControlremoteControl=newRemoteControl();
CeilingFanceilingFan=newCeilingFan("LivingRoom");//创建电扇对象
GarageDoorgarageDoor=newGarageDoor();//创建车库门对象
StereCDstereCD=newStereCD();//创建CD对象
Lightlight=newLight();//创建电灯对象
LightOnCommandlightOnCommand=newLightOnCommand(light);//创建开灯命令
LightOffCommandlightOffCommand=newLightOffCommand(light);//创建关灯命令
CeilingFanOnCommandceilingFanOn=newCeilingFanOnCommand(ceilingFan);//创建开电扇命令
CeilingFanOffCommandceilingFanOff=newCeilingFanOffCommand(ceilingFan);//创建关电扇命令
GarageDoorOnCommandgarageDoorOn=newGarageDoorOnCommand(garageDoor);//创建打开电扇命令
GarageDoorOffCommandgarageDoorOff=newGarageDoorOffCommand(garageDoor);//创建关闭电扇命令
StereCDOnCommandstereCDOn=newStereCDOnCommand(stereCD);//创建打开CD命令
StereCDOffCommandstereCDOff=newStereCDOffCommand(stereCD);//创建关闭CD命令
remoteControl.SetCommand(0,lightOnCommand,lightOffCommand);//将电灯命令设置到对应的控制器上
remoteControl.SetCommand(1,ceilingFanOn,ceilingFanOff);//将电灯命令设置到对应的控制器上
remoteControl.SetCommand(2,garageDoorOn,garageDoorOff);//将车库门命令设置到对应的控制器上
remoteControl.SetCommand(3,stereCDOn,stereCDOff);//将CD命令设置到对应的控制器上
remoteControl.OnButtonWasPressed(0);
remoteControl.OffButtonWasPressed(0);
remoteControl.OnButtonWasPressed
(1);
remoteControl.OffButtonWasPressed
(2);
remoteControl.OnButtonWasPressed(3);
remoteControl.OffButtonWasPressed(3);
1.5实现撤销命令
1.5.1修改命令接口,新增Undo()方法
voidUndo();//新增撤销方法
1.5.2修改命令,实现Undo方法
publicssLightOnCommand:
publicvoidUndo()//实现Undo方法
其他类都依次修改
1.5.3修改RemoteControl类,新增Command对象记录上一步操作
publicclassRemoteControlWithUndo
Command[]onCommands;
Command[]offCommands;
CommandundoCommand;//创建Command对象用来记录上一步执行的命令
publicRemoteControlWithUndo()
onCommands[i]=noCommand;
undoCommand=noCommand;
………
……..
undoCommand=onCommands[index];//记录打开命令
undoCommand=offCommands[index];//记录关闭命令
publicvoidUndoButtonWasPressed()//执行撤销
undoCommand.Undo();
……
1.6宏命令
让遥控器具有Party模式,即一个按键能够同步调用多个命令,这就是所谓的宏命令。
publicclassMacroCommand:
Command[]commands;//定义命令数组,用来接收传入的命令
publicMacroCommand(Command[]commands)
mands=commands;
publicvoidExecute()//批量处理多个命令(即初始化的时候传入的命令数组)
for(inti=0;icommands[i].Execute();}publicvoidUndo(){for(inti=0;icommands[i].Undo();}}2定义命令模式命令模式将“请求”封装成对象,以便使用不同的请求、队列或者日志来参数化其他对象。命令模式也支持可撤销的操作。定义命令模式类图:3命令模式的更多用途3.1队列请求命令将运算块打包,然后将它传来传去,即使在命令对象创建许久之后,运算依然可以被调用,甚至可以在不同的线程中被调用,我们可以利用这样的特性衍生一下应用,比如:日常安排、线程池、工作队列等。工作队列类和进行计算的对象之间完全是解耦的。它们只要是实现命令模式的对象就可以放到队列里边,当线程可用时就调用此对象的Execute()方法。3.2日志请求某些应用需要我们将所有动作记录到日志中,并在系统死机之后,重新调用这些动作恢复到之前的状态,命令模式就能够支持这一点。有许多调用大型数据结构的动作应用无法再每次改变发生时被快速的存储,通过使用记录日志,我们可以将上次检查点之后的所有操作记录下来,如果系统出现状况,可以从检查点开始应用这些操作。对于更高级的应用而言,这些技巧可以被扩展应用到事务处理中,即一整群操作必须全部完成,或者没有进行任何操作。3总结l命令模式将发出请求的对象和执行请求的对象解耦。l被解耦的两者之间是通过命令对象进行沟通的,命令对象封装了接收者和一个或一组动作。l调用者通过调用命令对象的Execute()发出请求,会使得接收者的动作被调用。l调用者可以接收命令当做参数,甚至在运行时动态进行。l命令可以支持撤销,做法是实现一个undo()方法来回到Execute()被执行之前的状态。l宏命令是命令的一种简单的延伸,允许调用多个命令,宏方法也可以支持撤销。l命令也可以用来实现日志和事务系统。
commands[i].Execute();
for(inti=0;icommands[i].Undo();}}2定义命令模式命令模式将“请求”封装成对象,以便使用不同的请求、队列或者日志来参数化其他对象。命令模式也支持可撤销的操作。定义命令模式类图:3命令模式的更多用途3.1队列请求命令将运算块打包,然后将它传来传去,即使在命令对象创建许久之后,运算依然可以被调用,甚至可以在不同的线程中被调用,我们可以利用这样的特性衍生一下应用,比如:日常安排、线程池、工作队列等。工作队列类和进行计算的对象之间完全是解耦的。它们只要是实现命令模式的对象就可以放到队列里边,当线程可用时就调用此对象的Execute()方法。3.2日志请求某些应用需要我们将所有动作记录到日志中,并在系统死机之后,重新调用这些动作恢复到之前的状态,命令模式就能够支持这一点。有许多调用大型数据结构的动作应用无法再每次改变发生时被快速的存储,通过使用记录日志,我们可以将上次检查点之后的所有操作记录下来,如果系统出现状况,可以从检查点开始应用这些操作。对于更高级的应用而言,这些技巧可以被扩展应用到事务处理中,即一整群操作必须全部完成,或者没有进行任何操作。3总结l命令模式将发出请求的对象和执行请求的对象解耦。l被解耦的两者之间是通过命令对象进行沟通的,命令对象封装了接收者和一个或一组动作。l调用者通过调用命令对象的Execute()发出请求,会使得接收者的动作被调用。l调用者可以接收命令当做参数,甚至在运行时动态进行。l命令可以支持撤销,做法是实现一个undo()方法来回到Execute()被执行之前的状态。l宏命令是命令的一种简单的延伸,允许调用多个命令,宏方法也可以支持撤销。l命令也可以用来实现日志和事务系统。
commands[i].Undo();
2定义命令模式
命令模式将“请求”封装成对象,以便使用不同的请求、队列或者日志来参数化其他对象。
命令模式也支持可撤销的操作。
定义命令模式类图:
3命令模式的更多用途
3.1队列请求
命令将运算块打包,然后将它传来传去,即使在命令对象创建许久之后,运算依然可以被调用,甚至可以在不同的线程中被调用,我们可以利用这样的特性衍生一下应用,比如:
日常安排、线程池、工作队列等。
工作队列类和进行计算的对象之间完全是解耦的。
它们只要是实现命令模式的对象就可以放到队列里边,当线程可用时就调用此对象的Execute()方法。
3.2日志请求
某些应用需要我们将所有动作记录到日志中,并在系统死机之后,重新调用这些动作恢复到之前的状态,命令模式就能够支持这一点。
有许多调用大型数据结构的动作应用无法再每次改变发生时被快速的存储,通过使用记录日志,我们可以将上次检查点之后的所有操作记录下来,如果系统出现状况,可以从检查点开始应用这些操作。
对于更高级的应用而言,这些技巧可以被扩展应用到事务处理中,即一整群操作必须全部完成,或者没有进行任何操作。
3总结
l命令模式将发出请求的对象和执行请求的对象解耦。
l被解耦的两者之间是通过命令对象进行沟通的,命令对象封装了接收者和一个或一组动作。
l调用者通过调用命令对象的Execute()发出请求,会使得接收者的动作被调用。
l调用者可以接收命令当做参数,甚至在运行时动态进行。
l命令可以支持撤销,做法是实现一个undo()方法来回到Execute()被执行之前的状态。
l宏命令是命令的一种简单的延伸,允许调用多个命令,宏方法也可以支持撤销。
l命令也可以用来实现日志和事务系统。
copyright@ 2008-2022 冰豆网网站版权所有
经营许可证编号:鄂ICP备2022015515号-1