前言:

本章会将封装带入到一个全新的境界,把方法调用封装起来。通过封装方法调用,把运算块包装成形。调用此运算的对象不需要知道事情是如何进行的,只要知道如何使用包装形成的方法来完成它就ok了。

1 现实场景应用

现在有一个遥控器,该遥控器有7个插槽需要编程,可以在每个插槽上放上不同的装置,然后用按钮控制它,这七个插槽具备各自的“开”“关”按钮,还有一个整体用的撤销按钮,会撤销最后一个按钮的动作。

1.1 创建第一个命令对象

1.1.1 定义命令接口
public interfaceCommand
{
void Execute();
}
1.1.2 实现一个打开灯的命令
publicclass Light //电灯类
{
public void On()
{
System.Console.WriteLine("Light is On !");
}
public void Off()
{
System.Console.WriteLine("Light is Off !");
}
}
public class LightOnCommand : Command//实现开灯命令
{
private Light light;
public LightOnCommand(Light light)
{
this.light = light;
}
public void Execute()
{
light.On();
}
}
1.1.3 使用命令对象
public class LightControl
{
privateCommand soft;
publicvoid SetCommand(Command cmd)
{
soft= cmd;//设置命令对象
}
publicvoid ButtonWasPressed()
{
soft.Execute();//调用命令对象的方法
}
}
1.1.4 简单测试
LightControl lightControl = new LightControl();//模拟命令的调用者
Lightlight = new Light();//创建一个电灯对象,作为命令的接收者
LightOnCommand lightOnCommand = new LightOnCommand(light);//创建一个命令,并将接受者传递给它
lightControl.SetCommand(lightOnCommand);//将命令传给调用者
lightControl.ButtonWasPressed();//模拟触发按钮

1.2 实现遥控器

public class RemoteControl
{
Command[] onCommands;//定义打开的命令数组
Command[] offCommands; //定义关闭的命令数组
public RemoteControl()
{
onCommands = new Command[7];
offCommands = new Command[7];
Command noCommand = newNoCommand();
for (int i = 0; i < 7; i++)
{
onCommands[i] = noCommand;//初始化命令数组(默认设置为无命令)
offCommands[i] = noCommand;
}
}
//将命令设置到对应的控制器
public void SetCommand(int index,Command onCommand, Command offCommand)
{
onCommands[index] = onCommand;
offCommands[index] = offCommand;
}
//触发打开控制器
public void OnButtonWasPressed(int index)
{
onCommands[index].Execute();
}
//触发关闭控制器
public void OffButtonWasPressed(intindex)
{
offCommands[index].Execute();
}
public override string ToString()
{
StringBuilder str = newStringBuilder();
str.Append("\n------RemoteControl ------\n");
for (int i = 0; i <onCommands.Length; i++)
{
str.Append("[solt" +i + "]" + onCommands[i].GetType().FullName + " " +offCommands[i].GetType().FullName + "\n");
}
return str.ToString();
}
}

1.3 实现其他控制器

 //关闭电灯命令
public classLightOffCommand : Command
{
privateLight light;
publicLightOffCommand(Light light)
{
this.light = light;
}
publicvoid Execute()
{
light.Off();
}
publicvoid Undo()
{
light.On();
}
}
//打开电扇命令
public class CeilingFanOnCommand : Command
{
CeilingFan ceilingFan;
intpreSpeed;
publicCeilingFanOnCommand(CeilingFan ceilingFan)
{
this.ceilingFan = ceilingFan;
}
publicvoid Execute()
{
ceilingFan.On();
}
publicvoid Undo()
{
ceilingFan.Off();
}
}
//关闭电扇命令
public classCeilingFanOffCommand : Command
{
CeilingFan ceilingFan;
publicCeilingFanOffCommand(CeilingFan ceilingFan)
{
this.ceilingFan = ceilingFan;
}
publicvoid Execute()
{
ceilingFan.Off();
}
publicvoid Undo()
{
ceilingFan.On();
}
}
//打开车库门命令
public classGarageDoorOnCommand : Command
{
GarageDoor garageDoor;
publicGarageDoorOnCommand(GarageDoor garageDoor)
{
this.garageDoor= garageDoor;
}
publicvoid Execute()
{
garageDoor.On();
}
publicvoid Undo()
{
garageDoor.Off();
}
}
//关闭车库门命令
public classGarageDoorOffCommand : Command
{
GarageDoor garageDoor;
publicGarageDoorOffCommand(GarageDoor garageDoor)
{
this.garageDoor = garageDoor;
}
publicvoid Execute()
{
garageDoor.Off();
}
publicvoid Undo()
{
garageDoor.On();
}
}
//打开CD命令
public classStereCDOnCommand : Command
{
StereCDstereCD;
publicStereCDOnCommand(StereCD stereCD)
{
this.stereCD = stereCD;
} publicvoid Execute()
{
stereCD.On();
}
publicvoid Undo()
{
stereCD.Off();
}
}
//关闭CD命令
public classStereCDOffCommand : Command
{
StereCDstereCD;
publicStereCDOffCommand(StereCD stereCD)
{
this.stereCD = stereCD;
}
publicvoid Execute()
{
stereCD.Off();
}
publicvoid Undo()
{
stereCD.On();
}
}

1.4简单测试

RemoteControlremoteControl = new RemoteControl ();
CeilingFan ceilingFan = newCeilingFan("Living Room");//创建电扇对象
GarageDoor garageDoor = newGarageDoor();//创建车库门对象
StereCD stereCD = new StereCD();//创建CD对象
Light light = new Light();//创建电灯对象
LightOnCommand lightOnCommand = newLightOnCommand(light);//创建开灯命令
LightOffCommand lightOffCommand =new LightOffCommand(light); //创建关灯命令
CeilingFanOnCommandceilingFanOn = new CeilingFanOnCommand(ceilingFan); //创建开电扇命令
CeilingFanOffCommand ceilingFanOff= new CeilingFanOffCommand(ceilingFan);//创建关电扇命令
GarageDoorOnCommand garageDoorOn =new GarageDoorOnCommand(garageDoor);//创建打开电扇命令
GarageDoorOffCommand garageDoorOff= new GarageDoorOffCommand(garageDoor);//创建关闭电扇命令
StereCDOnCommand stereCDOn = newStereCDOnCommand(stereCD);//创建打开CD命令
StereCDOffCommand stereCDOff = 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()方法
public interfaceCommand
{
void Execute();
void Undo();//新增撤销方法
}
1.5.2 修改命令,实现Undo方法
public class LightOnCommand : Command
{
private Light light;
public LightOnCommand(Light light)
{
this.light = light;
}
public void Execute()
{
light.On();
}
public void Undo()//实现Undo方法
{
light.Off();
}
}

其他类都依次修改

1.5.3 修改RemoteControl类,新增Command对象记录上一步操作
public class RemoteControlWithUndo
{
Command[] onCommands;
Command[] offCommands;
CommandundoCommand;//创建Command对象用来记录上一步执行的命令
publicRemoteControlWithUndo()
{
onCommands = new Command[7];
offCommands = new Command[7];
Command noCommand = new NoCommand();
for(int i = 0; i < 7; i++)
{
onCommands[i] = noCommand;
offCommands[i] = noCommand;
}
undoCommand = noCommand;
}
………
……..
publicvoid OnButtonWasPressed(int index)
{
onCommands[index].Execute();
undoCommand = onCommands[index];//记录打开命令
}
publicvoid OffButtonWasPressed(int index)
{
offCommands[index].Execute();
undoCommand = offCommands[index];//记录关闭命令
}
publicvoid UndoButtonWasPressed()//执行撤销
{
undoCommand.Undo();
}
……
……
}

1.6 宏命令

让遥控器具有Party模式,即一个按键能够同步调用多个命令,这就是所谓的宏命令。

 public class MacroCommand : Command
{
Command[] commands;//定义命令数组,用来接收传入的命令
public MacroCommand(Command[] commands)
{
this.commands = commands;
}
public void Execute()//批量处理多个命令(即初始化的时候传入的命令数组)
{
for (int i = 0; i <commands.Length; i++)
commands[i].Execute();
}
public void Undo()
{
for (int i = 0; i <commands.Length; i++)
commands[i].Undo();
}
}

2 定义命令模式

命令模式将“请求”封装成对象,以便使用不同的请求、队列或者日志来参数化其他对象。命令模式也支持可撤销的操作。

定义命令模式类图:

3 命令模式的更多用途

3.1 队列请求

命令将运算块打包,然后将它传来传去,即使在命令对象创建许久之后,运算依然可以被调用,甚至可以在不同的线程中被调用,我们可以利用这样的特性衍生一下应用,比如:日常安排、线程池、工作队列等。

工作队列类和进行计算的对象之间完全是解耦的。它们只要是实现命令模式的对象就可以放到队列里边,当线程可用时就调用此对象的Execute()方法。

3.2 日志请求

某些应用需要我们将所有动作记录到日志中,并在系统死机之后,重新调用这些动作恢复到之前的状态,命令模式就能够支持这一点。

有许多调用大型数据结构的动作应用无法再每次改变发生时被快速的存储,通过使用记录日志,我们可以将上次检查点之后的所有操作记录下来,如果系统出现状况,可以从检查点开始应用这些操作。对于更高级的应用而言,这些技巧可以被扩展应用到事务处理中,即一整群操作必须全部完成,或者没有进行任何操作。

3       总结

l  命令模式将发出请求的对象和执行请求的对象解耦。

l  被解耦的两者之间是通过命令对象进行沟通的,命令对象封装了接收者和一个或一组动作。

l  调用者通过调用命令对象的Execute()发出请求,会使得接收者的动作被调用。

l  调用者可以接收命令当做参数,甚至在运行时动态进行。

l  命令可以支持撤销,做法是实现一个undo()方法来回到Execute()被执行之前的状态。

l  宏命令是命令的一种简单的延伸,允许调用多个命令,宏方法也可以支持撤销。

l  命令也可以用来实现日志和事务系统。

Head First 设计模式之命令模式(CommandPattern)的更多相关文章

  1. 设计模式 ( 十三 ) 命令模式Command(对象行为型)

    设计模式 ( 十三 ) 命令模式Command(对象行为型) 1.概述         在软件设计中,我们经常需要向某些对象发送请求,但是并不知道请求的接收者是谁,也不知道被请求的操作是哪个,我们只需 ...

  2. 乐在其中设计模式(C#) - 命令模式(Command Pattern)

    原文:乐在其中设计模式(C#) - 命令模式(Command Pattern) [索引页][源码下载] 乐在其中设计模式(C#) - 命令模式(Command Pattern) 作者:webabcd ...

  3. 面向对象设计模式_命令模式(Command)解读

    在.Net框架中很多对象的方法中都会有Invoke方法,这种方法的设计实际是用了设计模式的命令模式, 模式图如下 其核心思路是将Client 向Receiver发送的命令行为进行抽象(ICommand ...

  4. 折腾Java设计模式之命令模式

    博客原文地址 折腾Java设计模式之命令模式 命令模式 wiki上的描述 Encapsulate a request as an object, thereby allowing for the pa ...

  5. 用Java 8 Lambda表达式实现设计模式:命令模式

    在这篇博客里,我将说明如何在使用 Java 8 Lambda表达式 的函数式编程方式 时实现 命令 设计模式 .命令模式的目标是将请求封装成一个对象,从对客户端的不同类型请求,例如队列或日志请求参数化 ...

  6. python设计模式之命令模式

    python设计模式之命令模式 现在多数应用都有撤销操作.虽然难以想象,但在很多年里,任何软件中确实都不存在撤销操作.撤销操作是在1974年引入的,但Fortran和Lisp分别早在1957年和195 ...

  7. Head First设计模式之命令模式

    一.定义 定义:将一个请求封装成一个对象,从而使您可以用不同的请求对客户进行参数化.对请求排队或记录请求日志,以及支持可撤消的操作. 主要解决:在软件系统中,行为请求者与行为实现者通常是一种紧耦合的关 ...

  8. Head First 设计模式 --6 命令模式

    命令模式:将"请求"封装成对象,以便使用不同的请求,队列或者日志来参数化其他对象.命令模式也支持可撤销的操作.用到的原则:1.封装变化2.组合优于继承3.针对接口编程,不能针对实现 ...

  9. C#设计模式(15)——命令模式(Command Pattern)

    一.前言 之前一直在忙于工作上的事情,关于设计模式系列一直没更新,最近项目中发现,对于设计模式的了解是必不可少的,当然对于设计模式的应用那更是重要,可以说是否懂得应用设计模式在项目中是衡量一个程序员的 ...

随机推荐

  1. 【转】 数据库系统——B+树索引

    原文来自于:http://blog.csdn.net/cjfeii/article/details/10858721 1. B+树索引概述 在上一篇文章中,我们讨论了关于index的几个中重要的课题: ...

  2. jQuery 的三种获取值的方式

    本节内容主要介绍的是如何使用jQuery中的.html(),.text()和.val()三种方法,用于读取,修改元素的html结构,元素的文本内容,以及表单元素的value值的方法.jQuery中为我 ...

  3. 【笔记】ListView的使用

    1.0 ListView三要素 1.0.1  创建基本步骤 1.在布局文件中创建一个ListView组件,并在Activity中声明这个组件. 2.在Activity中,创建一个合适的Adapter. ...

  4. SRS文档

    1什么是用例? 在介始用例方法之前,我们首先来看一下传统的需求表述方式-"软件需求规约"(Software Requirement Specification).传统的软件需求规约 ...

  5. maven 配置

    四.eclipse配置maven eclipse---window---maven------User Settings: 之前设置的仓库的位置: 五.idea15配置maven idea14---s ...

  6. 二叉树的实现与一些基本操作(C++环境)

    #include<cstdio>#include<cstdlib>#include<iostream>#include<cstring>using na ...

  7. RabbitMQ - TcpConnection析构引发的一次handshake_timeout

    使用RabbitMQ时,连接rabbit-server一直连接失败,代码没有任何错误提示.但是通过rabbitmqctl始终查询不到连接以及创建的queue等信息. 官方的文件demo里面也没有Tcp ...

  8. 【JS】falsy与truthy

    1.Falsy值,当进行逻辑判断时均为false(如!!false==false).六个Falsy值:false.undefined.null.正负0.NaN."". 2.其余所有 ...

  9. 2015.10.18 do while练习

    /*乘法表*/ #define COLMAX 10 #define ROWMAX 12 main() { int row,column,y; row=1; printf("          ...

  10. 暑假前的flag

    暑假到了,为了简便新开了一个博客,供暑假刷体放一些题解,玩acm1年多了,cf还是蓝名,真是菜的一笔,明年就大三了,马上就要毕业了,然而还是啥也不会,兼职和智障没什么两样,当初大一吹的牛逼说要成为学校 ...