14.Command命令(行为型模式)
Posted zzyzxb
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了14.Command命令(行为型模式)相关的知识,希望对你有一定的参考价值。
一、动机(Motivation)
<1>在软件构建过程中,“行为请求者”与“行为实现者”通常呈现一种“紧耦合”。但在某些场合——比如需要对行为进行“记录、撤销/重做(undo/redo)、事务”等处理,这种无法抵御变化的紧耦合是不合适的。
<2>在这种情况下,如何将“行为请求者”与“行为实现者”解耦?将一组行为抽象为对象,可以实现二者之间的松耦合。
二、意图(Intent)
将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化;对请求排队或记录请求日志,以及支持可撤销的操作。
——《设计模式》GoF
三、结构(Structure)
四、结构详解
五、生活中的例子
服务员接受顾客的点单,把它记在账单上封装。这个点单被排队等待烹饪。
六、实现
namespace Test
public class 厨师
//Action
public void 烤鸡翅(int 数量)
Console.WriteLine("厨师烤鸡翅:0", 数量);
//Action
public void 烤羊肉串(int 数量)
Console.WriteLine("厨师烤羊肉串:0", 数量);
//Command
public abstract class 命令
protected 厨师 _cook; //receiver接受者
public 命令(厨师 cook)
this._cook = cook;
//Execute执行
public abstract void 烧烤();
//State状态
public bool 执行完毕 = false;
private int _数量;
public int 数量
get
return this._数量;
set
if (value < 0)
Console.WriteLine("数量应>0");
else
this._数量 = value;
//ConcreteCommand具体命令
public class 烤鸡翅命令 : 命令
public 烤鸡翅命令(厨师 cook) : base(cook)
public override void 烧烤()
base._cook.烤鸡翅(base.数量);
this.执行完毕 = true;
//ConcreteCommand具体命令
public class 烤羊肉串命令 : 命令
public 烤羊肉串命令(厨师 cook) : base(cook)
public override void 烧烤()
base._cook.烤羊肉串(base.数量);
this.执行完毕 = true;
//Invoker
public class 服务员
private int 鸡翅数量 = 60;
private int 羊肉串数量 = 80;
private System.Collections.Generic.List<命令> orders = new List<命令>();
public void 下单(命令 command)
if (command is 烤鸡翅命令)
if (this.鸡翅数量 < command.数量)
Console.WriteLine("对不起,鸡翅不够了,现在只剩下:0", this.鸡翅数量);
return;
else
this.鸡翅数量 -= command.数量;
if (command is 烤羊肉串命令)
if (this.羊肉串数量 < command.数量)
Console.WriteLine("对不起,羊肉串不够了,现在只剩下:0", this.鸡翅数量);
return;
else
this.羊肉串数量 -= command.数量;
orders.Add(command);
Console.WriteLine("新下单:0,数量:1\\t2", command, command.数量, DateTime.Now);
public void 取消订单(命令 command)
if (command.执行完毕)
Console.WriteLine("订单已执行完毕,东西都吃到肚子里了.不能再取消");
return;
orders.Remove(command);
if (command is 烤鸡翅命令)
this.鸡翅数量 += command.数量;
else
this.羊肉串数量 += command.数量;
Console.WriteLine("订单已取消:" + command.ToString() + "\\t" + DateTime.Now.ToString());
public void 全部执行()
foreach (命令 cmd in orders)
if (!cmd.执行完毕)
cmd.烧烤();
internal class Program
static void Main(string[] args)
服务员 mm = new 服务员();
厨师 cook = new 厨师();
//30个鸡翅
命令 cmd30个鸡翅 = new 烤鸡翅命令(cook);
cmd30个鸡翅.数量 = 30;
//40个羊肉串
命令 cmd40个羊肉串 = new 烤羊肉串命令(cook);
cmd40个羊肉串.数量 = 40;
Console.WriteLine("========先来30个鸡翅,40个羊肉串=========");
mm.下单(cmd30个鸡翅);
mm.下单(cmd40个羊肉串);
mm.全部执行();
Console.WriteLine("========实在太爽了,再来40个鸡翅,50个羊肉串=========");
//40个鸡翅
命令 cmd40个鸡翅 = new 烤鸡翅命令(cook);
cmd40个鸡翅.数量 = 40;
//50个羊肉串
命令 cmd50个羊肉串 = new 烤羊肉串命令(cook);
cmd50个羊肉串.数量 = 50;
mm.下单(cmd40个鸡翅);
mm.下单(cmd50个羊肉串);
mm.全部执行();
Console.WriteLine("========不爽了,取消30个鸡翅,40个羊肉串=========");
mm.取消订单(cmd30个鸡翅);
mm.取消订单(cmd40个羊肉串);
Console.ReadLine();
实现结果
七、适用性
<1>使用命令模式作为“CallBack”在面向对象系统中的替代。“CallBack”讲的便是先将一个函数登记上,然后在以后调用此函数;
<2>需要在不同的时间指定请求、将请求排队。一个命令对象和原先的请求发出者可以有不同的生命期。换言之,原先的请求发出者可能已经不在了,而命令对象本身仍然是活动的。这时命令的接收者可以是在本地,也可以在网络的另外一个地址。命令对象可以在串形化之后传送到另外一台机器上去;
<3>系统需要支持命令的撤消(undo)。命令对象可以把状态存储起来,等到客户端需要撤销命令所产生的效果时,可以调用undo()方法,把命令所产生的效果撤销掉。命令对象还可以提供redo()方法,以供客户端在需要时,再重新实施命令效果;
<4>如果一个系统要将系统中所有的数据更新到日志里,以便在系统崩溃时,可以根据日志里读回所有的数据更新命令,重新调用Execute()方法一条一条执行这些命令,从而恢复系统在崩溃前所做的数据更新。
八、总结
<1>Command模式是非常简单而又优雅的一种设计模式,它的根本目的在于将“行为请求者”与“行为实现者”解耦;
<2>Command模式的根本目的在于将“行为请求者”与“行为实现者”解耦,在面向对象语言中,常见的实现手段是“将行为抽象为对象”;
<3>实现Command接口的具体命令对象ConcreteCommand有时候根据需要可能会保存一些额外的状态信息;
<4>通过使用Compmosite模式,可以将多个命令封装为一个“复合命令”MacroCommand;
<5>Command模式与C#中的Delegate有些类似。但两者定义行为接口的规范有所区别:Command以面向对象中的“接口-实现”来定义行为接口规范,更严格,更符合抽象原则;Delegate以函数签名来定义行为接口规范,更灵活,但抽象能力比较弱;
<6>使用命令模式会导致某些系统有过多的具体命令类。某些系统可能需要几十个,几百个甚至几千个具体命令类,这会使命令模式在这样的系统里变得不实际。
17行为型模式之命令模式
概念
Command模式也叫命令模式 ,是行为设计模式的一种。Command模式通过被称为Command的类封装了对目标对象的调用行为以及调用参数。
在面向对象的程序设计中,一个对象调用另一个对象,一般情况下的调用过程是:创建目标对象实例;设置调用参数;调用目标对象的方法。
但在有些情况下有必要使用一个专门的类对这种调用过程加以封装,我们把这种专门的类称作command类。
整个调用过程比较繁杂,或者存在多处这种调用。这时,使用Command类对该调用加以封装,便于功能的再利用。-
调用前后需要对调用参数进行某些处理。调用前后需要进行某些额外处理,比如日志,缓存,记录历史操作等。
角色和职责
Command
Command命令的抽象类。
ConcreteCommand
Command的具体实现类。
Receiver
需要被调用的目标对象。
Invorker
通过Invorker执行Command对象。
适用于:
是将一个请求封装为一个对象,从而使你可用不同的请求对客户端进行参数化;对请求排队或记录请求日志,以及支持可撤销的操作。
案例
//根据输入不同的命令,出售不同的水果
#include <iostream> using namespace std; #include "list" class Vendor { public: void sailbanana() { cout << "卖香蕉" << endl; } void sailapple() { cout << "卖苹果" << endl; } }; class Command { public: virtual void sail() = 0; }; class BananaCommand : public Command { public: BananaCommand(Vendor *v) { m_v = v; } Vendor *getV(Vendor *v) { return m_v; } void setV(Vendor *v) { m_v = v; } virtual void sail() { m_v->sailbanana(); } protected: private: Vendor *m_v; }; class AppleCommand : public Command { public: AppleCommand(Vendor *v) { m_v = v; } Vendor *getV(Vendor *v) { return m_v; } void setV(Vendor *v) { m_v = v; } virtual void sail() { m_v->sailapple(); } protected: private: Vendor *m_v; }; class Waiter { public: Command *getCommand() { return m_command; } void setCommand(Command *c) { m_command = c; } void sail() { m_command->sail(); } protected: private: Command *m_command; }; class AdvWaiter { public: AdvWaiter() { m_list = new list<Command *>; m_list->resize(0); } ~AdvWaiter() { delete m_list; } void setCommands(Command *c) { m_list->push_back(c); } list<Command *> * getCommands() { return m_list; } void sail() { for (list<Command *>::iterator it=m_list->begin(); it!=m_list->end(); it++ ) { (*it)->sail(); } } protected: private: list<Command *> *m_list; }; //小商贩 直接 卖 水果 void main25_01() { Vendor *v = new Vendor; v->sailapple(); v->sailbanana(); delete v; return ; } //小商贩 通过命令 卖 水果 void main25_02() { Vendor *v = new Vendor; AppleCommand *ac = new AppleCommand(v); ac->sail(); BananaCommand *bc = new BananaCommand(v); bc->sail(); delete bc; delete ac; delete v; } //小商贩 通过waiter 卖 水果 void main25_03() { Vendor *v = new Vendor; AppleCommand *ac = new AppleCommand(v); BananaCommand *bc = new BananaCommand(v); Waiter *w = new Waiter; w->setCommand(ac); w->sail(); w->setCommand(bc); w->sail(); delete w; delete bc; delete ac; delete v; } //小商贩 通过advwaiter 批量下单 卖水果 void main25_04() { Vendor *v = new Vendor; AppleCommand *ac = new AppleCommand(v); BananaCommand *bc = new BananaCommand(v); AdvWaiter *w = new AdvWaiter; w->setCommands(ac); w->setCommands(bc); w->sail(); delete w; delete bc; delete ac; delete v; } void main() { //main25_01(); //main25_02(); //main25_03(); main25_04(); system("pause"); }
以上是关于14.Command命令(行为型模式)的主要内容,如果未能解决你的问题,请参考以下文章