深入浅出设计模式——命令模式(Command Pattern)

时间:2023-03-09 07:54:17
深入浅出设计模式——命令模式(Command Pattern)

模式动机
深入浅出设计模式——命令模式(Command Pattern)

在软件设计中,我们经常需要向某些对象发送请求,但是并不知道请求的接收者是谁,也不知道被请求的操作是哪个,我们只需在程序运行时指定具体的请求接收者即可,此时,可以使用命令模式来进行设计,使得请求发送者与请求接收者消除彼此之间的耦合,让对象之间的调用关系更加灵活。
命令模式可以对发送者和接收者完全解耦,发送者与接收者之间没有直接引用关系,发送请求的对象只需要知道如何发送请求,而不必知道如何完成请求。这就是命令模式的模式动机。

模式定义
命令模式(Command Pattern):将一个请求封装为一个对象,从而使我们可用不同的请求对客户进行参数化;对请求排队或者记录请求日志,以及支持可撤销的操作。命令模式是一种对象行为型模式,其别名为动作(Action)模式或事务(Transaction)模式。
Command Pattern: Encapsulate a request as an object, thereby letting you parameterize clients with different requests, queue or log requests, and support undoable operations.
Frequency of use: medium high
UML图
深入浅出设计模式——命令模式(Command Pattern)

模式结构
命令模式包含如下角色:
Command: 抽象命令类
ConcreteCommand: 具体命令类
Invoker: 调用者
Receiver: 接收者
Client:客户类

模式分析
命令模式的本质是对命令进行封装,将发出命令的责任和执行命令的责任分割开。
每一个命令都是一个操作:请求的一方发出请求,要求执行一个操作;接收的一方收到请求,并执行操作。
命令模式允许请求的一方和接收的一方独立开来,使得请求的一方不必知道接收请求的一方的接口,更不必知道请求是怎么被接收,以及操作是否被执行、何时被执行,以及是怎么被执行的。

命令模式使请求本身成为一个对象,这个对象和其他对象一样可以被存储和传递。
命令模式的关键在于引入了抽象命令接口,且发送者针对抽象命令接口编程,只有实现了抽象命令接口的具体命令才能与接收者相关联。

模式实例与解析
烤羊肉串引来的思考—命令模式
体系结构
深入浅出设计模式——命令模式(Command Pattern)

Command: 抽象命令类 Command.cs

namespace CommandPattern
{
//抽象命令类
public abstract class Command
{
protected Barbecuer receiver;
public Command(Barbecuer receiver)
{
this.receiver = receiver;
}
//执行命令
abstract public void ExecuteCommand();
}
}

ConcreteCommand: 具体命令类 BakeMuttonCommand.cs

namespace CommandPattern
{
//烤羊肉串命令
class BakeMuttonCommand : Command
{
public BakeMuttonCommand(Barbecuer receiver)
: base(receiver)
{
}
public override void ExecuteCommand()
{
receiver.BakeMutton();
}
}
}

BakeChickenWingCommand.cs

namespace CommandPattern
{
//烤鸡翅命令
class BakeChickenWingCommand : Command
{
public BakeChickenWingCommand(Barbecuer receiver)
: base(receiver)
{
}
public override void ExecuteCommand()
{
receiver.BakeChickenWing();
}
}
}

Invoker: 调用者 Waiter.cs

using System;
using System.Collections.Generic; namespace CommandPattern
{
//服务员
public class Waiter
{
//增加存放具体命令的容器
private IList<Command> orders = new List<Command>(); //设置订单
public void SetOrder(Command command)
{
if (command.ToString() == "CommandPattern.BakeChickenWingCommand")
{
Console.WriteLine("服务员:鸡翅没有了,请点别的烧烤.");
}
else
{
orders.Add(command);
Console.WriteLine("增加订单:" + command.ToString() + " 时间:" + DateTime.Now.ToString());
}
}
//取消订单
public void CancelOrder(Command command)
{
orders.Remove(command);
Console.WriteLine("取消订单:" + command.ToString() + " 时间:" + DateTime.Now.ToString());
}
//通知全部执行
public void Notify()
{
foreach (Command cmd in orders)
{
cmd.ExecuteCommand(); }
}
}
}

Receiver: 接收者 Barbecuer.cs

using System;

namespace CommandPattern
{
//烤肉串者
public class Barbecuer
{
//烤羊串
public void BakeMutton()
{
Console.WriteLine("烤羊肉串!");
}
public void BakeChickenWing()
{
Console.WriteLine("烤鸡翅!");
}
}
}

Client:客户类

using System;

namespace CommandPattern
{
class Program
{
static void Main(string[] args)
{
//开店前的准备
Barbecuer boy = new Barbecuer();
Command bakeMuttonCommand1 = new BakeMuttonCommand(boy);
Command bakeMuttonCommand2 = new BakeMuttonCommand(boy);
Command bakeChikenWingCommand1 = new BakeChickenWingCommand(boy);
Waiter girl = new Waiter();
//开门营业 顾客点菜
girl.SetOrder(bakeMuttonCommand1);
girl.SetOrder(bakeMuttonCommand2);
girl.SetOrder(bakeChikenWingCommand1);
//点菜完毕,通知厨房
girl.Notify(); Console.Read();
}
}
}

模式优缺点
命令模式的优点
 降低系统的耦合度。
 新的命令可以很容易地加入到系统中。
 可以比较容易地设计一个命令队列和宏命令(组合命令)。
 可以方便地实现对请求的Undo和Redo。

命令模式的缺点
 使用命令模式可能会导致某些系统有过多的具体命令类。因为针对每一个命令都需要设计一个具体命令类,因此某些系统可能需要大量具体命令类,这将影响命令模式的使用。

模式适用环境
在以下情况下可以使用命令模式:
 系统需要将请求调用者和请求接收者解耦,使得调用者和接收者不直接交互。
 系统需要在不同的时间指定请求、将请求排队和执行请求。
 系统需要支持命令的撤销(Undo)操作和恢复(Redo)操作。
 系统需要将一组操作组合在一起,即支持宏命令。

【声明与感谢】
本文,站在许多巨人的肩膀上,借鉴和引用了许多他人拥有版权的作品或著述,在此,对前人们的贡献致谢。并同时公布引用的内容、原作者或来源(一些来源于互联网的内容本人无法追述本源,深表遗憾)。

【参考文献】
《设计模式—可复用面向对象软件的基础》作者: [美] Erich Gamma / Richard Helm / Ralph Johnson / John Vlissides 译者: 李英军 / 马晓星 / 蔡敏 / 刘建中 等 机械工业出版社
《重构—改善既有代码的设计》作者: Martin Fowler译者:候捷 中国电力出版社
《敏捷软件开发—原则、模式与实践》作者: Robert C. Martin 清华大学出版社
《程序员修炼之道—从小工到专家》作者: Andrew Hunt / David Thomas 电子工业出版社
《Head First 设计模式》作者: 弗里曼 译者: O'Reilly *公司 中国电力出版社
《设计模式之禅》 作者: 秦小波 机械工业出版社
MSDN WebCast 《C#面向对象设计模式纵横谈》 讲师:李建忠
刘伟. 设计模式. 北京:清华大学出版社, 2011.
刘伟. 设计模式实训教程. 北京:清华大学出版社, 2012.
《大话设计模式》 作者: 程杰 清华大学出版社
《C#图解教程》作者: 索利斯 译者: 苏林 / 朱晔 人民邮电出版社
《你必须知道的.NET》作者: 王涛
《项目中的.NET》作者: 李天平 电子工业出版社
《Microsoft .NET企业级应用架构设计》作者: (美)埃斯波西托等编著 译者: 陈黎夫
http://www.dofactory.com/Patterns/Patterns.aspx .NET Design Patterns
http://www.cnblogs.com/zhenyulu 博客作者:吕震宇
http://www.cnblogs.com/terrylee 博客作者:李会军
http://www.cnblogs.com/anlyren/ 博客作者:anlyren
http://www.cnblogs.com/idior 博客作者:idior
http://www.cnblogs.com/allenlooplee 博客作者:Allen lee
http://blog.csdn.net/ai92 博客作者:ai92
http://www.cnblogs.com/umlonline/ 博客作者:张传波
http://www.cnblogs.com/lovecherry/ 博客作者:LoveCherry