前言:

本章会将封装带入到一个全新的境界,把方法调用封装起来。通过封装方法调用,把运算块包装成形。调用此运算的对象不需要知道事情是如何进行的,只要知道如何使用包装形成的方法来完成它就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. 亲身试用python简单小爬虫

    前几天基友分享了一个贴吧网页,有很多漂亮的图片,想到前段时间学习的python简单爬虫,刚好可以实践一下. 以下是网上很容易搜到的一种方法: #coding=utf-8 import urllib i ...

  2. entity framework 新手入门篇(1.5)-lambda表达式与linq

    在建立好了EF模型之后,先不着急使用它,在使用它之前,你还需要了解两个相关的技术,lambda表达式与linq. 作为微软C#语言中重要的语法糖-lambda表达式与LINQ,本质都是一个方法,以la ...

  3. TeamWork-天气美食

    一.  团队情况      Hello,欢迎来到我们"Code Man"队的第一次团队作业页面,"代码侠"很明显我们是一个编程队伍,由大三在读的6位同班同学组成 ...

  4. BZOJ 2002 && BZOJ 2409 LCT && BZOJ 3282 初步练习

    #include <cstdio> ; inline void Get_Int(int & x) { ; ') ch=getchar(); +ch-'; ch=getchar(); ...

  5. C/C++读入一行不定个数的整数

    我想,每个人一开始遇到这个问题,都会觉得挺简单的.但真正实施的时候,可能就会觉得还是有点坑的.毕竟对于C/C++这样成熟而使用广泛的语言而言,对于这个简单的问题竟然没有一个简洁有力甚至一行代码的解决方 ...

  6. 软件测试第三次作业——7.使用下面方法printPrimes()完成后面的问题(a)~(f)

    (a)控制流图如下: (b)令MAXPRIMES=4,会出现越界错误. (c)令n=1,不会经过while循环体. (d)节点覆盖:{1,2,3,4,5,6,7,8,9,10,11,12,13,14, ...

  7. WPF(WP7、WP8)实现圆形图片

    在WP平台上制作图片圆角其实特别简单, 用Image控件的Clip属性即可(RadiusX-Y设置为图片尺寸的一半) <Image Source="{Binding photo}&qu ...

  8. (转) Xcode 7 Bitcode

    Xcode 7 Bitcode的工作流程及安全性评估 2015-12-18 06:13 编辑: suiling 分类:iOS开发 来源:FreeBuf黑客与极客 简介 随着 Xcode 7 的发布,苹 ...

  9. MVC 从后台页面 取前台页面传递过来的值的几种取法

      MVC 从后台页面 取前台页面传递过来的值的几种取法   <1>前台页面 Index视图 注意:用户名表单的name值为txtName 密码表单的name值为txtPassword & ...

  10. 关于对CSS尺寸单位'em'的长期误解

    一直以来认为'em'是相对于父元素的字体大小. 直到今天学习移动WEB开发,重新复习css的尺寸大小时,惊奇发现:对em深深的误解了!!! 在CSS官网对em的解释实例是: a. h1{line-he ...