Head First 设计模式之命令模式(CommandPattern)
前言:
本章会将封装带入到一个全新的境界,把方法调用封装起来。通过封装方法调用,把运算块包装成形。调用此运算的对象不需要知道事情是如何进行的,只要知道如何使用包装形成的方法来完成它就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)的更多相关文章
- 设计模式 ( 十三 ) 命令模式Command(对象行为型)
设计模式 ( 十三 ) 命令模式Command(对象行为型) 1.概述 在软件设计中,我们经常需要向某些对象发送请求,但是并不知道请求的接收者是谁,也不知道被请求的操作是哪个,我们只需 ...
- 乐在其中设计模式(C#) - 命令模式(Command Pattern)
原文:乐在其中设计模式(C#) - 命令模式(Command Pattern) [索引页][源码下载] 乐在其中设计模式(C#) - 命令模式(Command Pattern) 作者:webabcd ...
- 面向对象设计模式_命令模式(Command)解读
在.Net框架中很多对象的方法中都会有Invoke方法,这种方法的设计实际是用了设计模式的命令模式, 模式图如下 其核心思路是将Client 向Receiver发送的命令行为进行抽象(ICommand ...
- 折腾Java设计模式之命令模式
博客原文地址 折腾Java设计模式之命令模式 命令模式 wiki上的描述 Encapsulate a request as an object, thereby allowing for the pa ...
- 用Java 8 Lambda表达式实现设计模式:命令模式
在这篇博客里,我将说明如何在使用 Java 8 Lambda表达式 的函数式编程方式 时实现 命令 设计模式 .命令模式的目标是将请求封装成一个对象,从对客户端的不同类型请求,例如队列或日志请求参数化 ...
- python设计模式之命令模式
python设计模式之命令模式 现在多数应用都有撤销操作.虽然难以想象,但在很多年里,任何软件中确实都不存在撤销操作.撤销操作是在1974年引入的,但Fortran和Lisp分别早在1957年和195 ...
- Head First设计模式之命令模式
一.定义 定义:将一个请求封装成一个对象,从而使您可以用不同的请求对客户进行参数化.对请求排队或记录请求日志,以及支持可撤消的操作. 主要解决:在软件系统中,行为请求者与行为实现者通常是一种紧耦合的关 ...
- Head First 设计模式 --6 命令模式
命令模式:将"请求"封装成对象,以便使用不同的请求,队列或者日志来参数化其他对象.命令模式也支持可撤销的操作.用到的原则:1.封装变化2.组合优于继承3.针对接口编程,不能针对实现 ...
- C#设计模式(15)——命令模式(Command Pattern)
一.前言 之前一直在忙于工作上的事情,关于设计模式系列一直没更新,最近项目中发现,对于设计模式的了解是必不可少的,当然对于设计模式的应用那更是重要,可以说是否懂得应用设计模式在项目中是衡量一个程序员的 ...
随机推荐
- c# 远程连接ORACLE数据库
使用该方法,只需要传入几个必要的参数就可以进行数据库的远程连接测试了,连接成功返回TRUE,失败返回false. 说明: 第一个参数表示你在数据库中的用户,具有可以登录权限的 第二个参数表示用户的密码 ...
- docker 源码分析 四(基于1.8.2版本),Docker镜像的获取和存储
前段时间一直忙些其他事情,docker源码分析的事情耽搁了,今天接着写,上一章了解了docker client 和 docker daemon(会启动一个http server)是C/S的结构,cli ...
- Arraylist<E>
ArrayList 应该是大部分人接触JCF之后, 第一个熟悉和使用的类.它的特点主要有一下几个: 1. 基于数组 public ArrayList(int initialCapacity) { if ...
- html 涂改图片功能实现
网页源码直接贴了: <!DOCTYPE html> <html> <head> <meta charset="utf-8"> < ...
- ThinkPHP M函数疑点
模型类的命名规则是除去表前缀的数据表名称,采用驼峰法命名,并且首字母大写,然后加上模型层的名称(默认定义是Model),例如: 模型名 约定对应数据表(假设数据库的前缀定义是 think_) User ...
- LinQ递归查询
--由父项递归下级 with cte(refid,pid,zname,code) as (--父项 union all --递归结果集中的下级 select t.refid,t.pid,t.zname ...
- ansible代码分析第一篇--主文件—ansible分析
2016年2月23日,学习,分析ansible代码 ansible是一种运维中使用的批量部署的工具,它本身是一种框架,具体的部署和架构分析,下面这篇文章讲的不错. http://os.51cto.co ...
- Android RadioButton 语言无法切换问题
1.Dialog在不退出界面的情况下,RadioButton在语言切换时,无法匹配系统语言的问题: 解决办法为:在RadioButton添加属性 android:saveEnabled="f ...
- OpenStack虚拟机DHCP获取不到IP地址排查
版本:OpenStack Liberty Neutron DVR 现象: 1.在虚拟机内部不停地dhclient 2.在虚拟机所属的计算节点的物理网卡上抓包,发现该虚拟机发出的dhcp广播包 3.在虚 ...
- libevent之丢失header问题
本文为原创,转载请注明:http://www.cnblogs.com/gistao/ 背景 分享一个hhvm使用http server方式来处理请求的问题及对应的patch.hhvm3+版本支持fas ...