定义:将一个请求封装成一个对象,从而使你可用不同的请求对客户进行参数化,对请求排队或记录请求日志,以及支持可撤销的操作。
路边烤羊肉串的实现
烤羊串者类 两个方法 一个是烤羊肉 一个是烤鸡翅
松耦合设计
// 抽象命令
public abstract class Command {
protected Barbecuer receiver;
public Command(Barbecuer receiver){
this.receiver = receiver;
}
abstract public void ExecuteCommand();
}
class BakeMuttonCommand : Command {
public BakeMuttonCommand(Barbecuer receiver) {}
public override void ExecuteCommand(){
receiver.BakeMutton();
}
}
class BakeChickenWingCommand : Command{
public BakeChickenWingCommand(Barbecuer receiver) {}
public override void ExecuteCommand(){
receiver.BakeChickenWing();
}
}
// 服务员
public class Waiter {
private Command command;
public void SetOrder(Command com) {
this.command = com;
}
//通知执行
public void Notify(){
command.ExecuteCommand();
}
}
static void Main(string []args){
//开店前的准备
Barbecuer boy = new Barbecuer();
Command b1 = new BakeMuttonCommand(boy);
Command b2 = new BakeMuttonCommand(boy);
Command b3 = new BakeChickenWingCommand(boy);
Waiter girl = new Waiter();
// 开门营业
girl.SetOrder(b1);
girl.Notify();
girl.SetOrder(b2);
girl.Notify();
girl.SetOrder(b3);
girl.Notify();
}
几个问题点需要改进:真实的情况不是用户点一个菜,服务员就通知厨房去做,应该是点完烧烤后,服务员一次通知制作,
2.如果此时鸡翅没了,不应该是客户来判断有没有,应该是服务员或是烤肉串来否决这个请求
3.客户点了哪些烧烤,这是需要记录日志的,以备收费
4.客户有可能取消部分订单等。
改进后代码如下:
public class Waiter {
private IList<Command> orders = new List<>();
//设置订单
public void SetOrder(Command command){
if(command.ToString == "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 NotifyAll(){
foreach(Command cmd in orders){
cmd.ExecuteCommand();
}
}
}
static void Main(String[]args){
//开店前的准备
Barbecuer boy = new Barbecuer();
Command b1 = new BakeButtonCommand(boy);
Command b2 = new BakeButtonCommand(boy);
Command b3 = new BakeChickenWingCommand(boy);
Waiter girl = new Waiter();
// 开门营业 顾客点菜
girl.SetOrder(b1);
girl.SetOrder(b2);
girl.SetOrder(b3);
// 点菜完毕 通知厨房 一次性通知
girl.NotifyAll();
}
// 用来声明执行操作的接口
abstract class Command {
protected Receiver receiver;
public Command(Receiver receiver) {
this.receiver = receiver;
}
abstract public void Execute();
}
class ConcreteCommand : Command {
public ConcreteCommand(Receiver receiver)
{}
public override void Execute() {
receiver.Action();
}
}
class Invoker {
private Command command;
public void SetCommand(Command cod) {
this.command = cod;
}
public void ExecuteCommand() {
command.Execute();
}
}
class Receiver {
public void Action(){
Console.WriteLine("执行请求!");
}
}
//客户端代码,创建一个具体命令对象并设定它的接收者
static void Main(string[] args){
Receiver r = new Receiver();
Command c = new ConcreteCommand(r);
Invoke i = new Invoke();
i.SetCommand(c);
i.ExecuteCommand();
}
命令模式的优点:
1.它能较容易地设计一个命令队列
2.在需要的情况下,可以较容易的将命令记入日志
3.允许接收请求的一方决定是否要否决请求
4.可以容易地实现对请求的撤销和重做
5.由于加进新的具体命令类不影响其他的类,因此增加新的具体命令类很容易,
6.命令模式把请求一个操作的对象与知道怎么执行一个操作的对象分割开。
敏捷开发原则告诉我们,不要为代码添加基于猜测的、实际不需要的功能。如果不清楚一个系统是否需要命令模式,一般就不要着急去实现它,事实上,在需要的时候通过重构实现这个模式并不困难,只有在真正需要如撤销/恢复等操作功能时,把原来的代码重构为命令模式才有意义。