第23章 烤羊肉串引来的思考——命令模式
以餐馆为例,若请求的实现者:厨师,既要去实现请求:去炒菜,又要对请求进行排队或纪录请求日志,以及支持可撤销的操作等,着显然会造成混乱,责任划分不明确。
同样以餐馆为例,行为请求着:客户,显然不必要了解行为实现过程,甚至不需要知道行为实现者是谁,只需要与服务员打交道即可。让服务员负责纪录请求,进行请求的纪录、撤销等更加合适。
还是以餐馆为例:我们可以把请求泛化处一个抽象类,让“服务员”直观对抽象的“命令”发号施令就可以了。具体事什么命令,有客户来决定就可以了。
¥:在命令(Command)模式中,对¥[命令]进行封装,命令中引用处理者,处理者具体负责处理请求。命令模式中还有¥[Invoker]角色负责管理¥[Command],负责Command的启动处理,删除请求,更新请求等。用户直接把请求交给Invoker角色即可。
¥:命令模式(Command),将一个请求封装为一个对象,从而使你可以用不同的请求对客户进行参数化;对请求排队或则纪录请求日志,以及支持可撤销的操作。优点:
第一,他能较容易地设计一个¥[命令队列];
第二,在需要的情况下,可以较容易地将命令计入日志;
第三,允许接受请求的一方决定¥[是否接受]请求,如,你到餐馆中订了一盘糖醋鱼,结果没有材料了,服务员就可以及时的提醒客户。
第四,可以较容易地实现对请求的¥[撤销]和重做;
第五,可以¥[加入]新的具体命令类而¥[不影响]其他的类。
最后,命令模式可以把请求一个操作的对象与¥[知道]怎样执行一个操作的对象分割开,避免‘行为请求者’和‘行为实现者’之间的¥[紧耦合]。
¥:是否在碰到类似情况是一定要用命令模式?
敏捷开发的原则告诉我们,不要为代码添加基于¥[猜测]的、实际¥[不需要]的功能。如果不清楚一个系统是否需要命令模式,一般就不要急着去实现它,事实上,在需要的时候通过重构实现这个模式并不困难,只是在真正需要如何撤销/恢复操作等功能时,把原来的代码重构为命令模式才有意义。
¥:¥[barbecue] |ˈbɑːbɪkjuː| A.noun 户外烧烤、烤架、烧烤 B.transitive verb 烧烤/¥[bake] |beɪk| verb 烘、烤/¥[mutton] |ˈmʌtn| noun 羊肉/¥[wing] |wɪŋ| noun 翅膀/¥[chicken] wing:鸡翅/¥[command] |kəˈmɑːnd, American -ˈmænd| noun 命令/¥[execute] |ˈeksɪkjuːt| verb 执行、实施、履行 execute command/¥[notify] |ˈnəʊtɪfaɪ| verb 通知 to notify [somebody] that ... 通知某人… notify somebody that execute command
abstract class Command
{
protected Receiver receiver;
public Command(Receiver receiver)
{
this.receiver = receiver;
}
abstract public void Execute();
}
class ConcreteCommand:Command
{
public ConcreteCommand(Receiver receiver) : base(receiver)
{
}
public override void Execute()
{
receiver.Action();
}
}
class Invoker
{
private Command command;
public void SetCommand(Command command)
{
this.command = command;
}
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); //可以理解为准备菜单
Invoker i = new Invoker();
i.SetCommand(c);//可以理解为客户点菜
i.ExecuteCommand();
Console.Read();
}
23.3 紧耦合设计
//烤肉串者
public class Barbecuer
{
//烤羊肉
public void BakeMutton()
{
Console.WriteLine(“烤羊肉”);
}
//烤鸡翅
public void BakeChickenWing()
{
Console.WriteLine(“烤鸡翅”);
}
}
客户端调用
static void Main(string[] args)
{
Barbecuer boy = new Barbecuer();
boy. BakeMutton();
boy. BakeMutton();
boy. BakeMutton();
boy. BakeChickenWing();
boy. BakeMutton();
boy. BakeMutton();
boy. BakeChickenWing();
Console.Read();
}
23.4 松耦合设计
//抽象命令
public abstract class Command
{
protected Barbecuer receiver;
// 抽象命令类,只需要确定‘烤肉串者’是谁
public Command(Barbecuer receiver)
{
this. receiver= receiver;
}
//执行命令
abstract public void ExcuteCommand();
}
//烤羊肉串命令类
class BakeMuttonCommand : Command
{
public BakeMuttonCommand(Barbecuer receiver) :base(receiver){ }
public override void ExcuteCommand()
{
receiver.BakeMutton();
}
}
//烤鸡翅命令
class BakeChickenWingCommand : Command
{
public BakeChickenWingCommand(Barbecuer receiver) :base(receiver){ }
public override void ExcuteCommand()
{
receiver.BakeMutton();
}
}
//服务员
public class Waiter
{
private Command command;
//设置订单,服务员类,不用管用户想要什么烤肉,反正都是‘命令’,只管记录订单,然后通知‘烤肉串者’执行即可。
public void SetOrder(Command command)
{
this.command = command;
}
//通知执行
public void Notify()
{
command. ExcuteCommand();
}
}
static void Main(string[] args)
{
//开店前的准备
Barbecuer boy = new Barbecuer();
Command bakeMuttonCommand1 = new BakeMuttonCommand(boy);
Command bakeMuttonCommand2 = new BakeMuttonCommand(boy);
Command bakeChickenWingComman1 = new BakeChickenWingCommand(boy);
Waiter girl = new Waiter();
//开门营业,来一个订单就通知一下是不合适的。
girl.SetOrder(bakeMuttonCommand1);
girl.Notify();
girl.SetOrder(bakeMuttonCommand2);
girl.Notify();
girl.SetOrder(bakeChickenWingComman1);
girl.Notify();
Console.Read();
}
23.5 松耦合后
//服务员
public class Waiter
{
private IList<Command> orders = new List<Command>();
//设置订单
public void SetOrder(Command command)
{
if (command.ToString() == “Command. BakeChickenWingCommand”)
{
Console.WriteLine(“没有鸡翅了”);
}
else
{
orders.Add(command);
Console.WriteLine(“增加一个订单”);
}
}
//取消订单
public void CancelOrder(Command command)
{
orders.Remove(command);
Console.WriteLine(“取消一个订单”);
}
//通知全部执行
public void Notify()
{
foreach(Command cmd in orders)
{
cmd.ExcuteCommand();
}
}
}
static void Main(string[] args)
{
//开店前的准备
Barbecuer boy = new Barbecuer();
Command bakeMuttonCommand1 = new BakeMuttonCommand(boy);
Command bakeMuttonCommand2 = new BakeMuttonCommand(boy);
Command bakeChickenWingComman1 = new BakeChickenWingCommand(boy);
Waiter girl = new Waiter();
//开门营业,来一个订单就通知一下是不合适的。
girl.SetOrder(bakeMuttonCommand1);
girl.SetOrder(bakeMuttonCommand2);
girl.SetOrder(bakeChickenWingComman1);
//点菜完毕,通知厨房
girl.Notify();
Console.Read();
}
23.6 命令模式
Receiver类
class Receiver
{
public void Action()
{
Console.WriteLine(“执行请求!”);
}
}
Command类
abstract class Command
{
protected Receiver receiver;
public Command(Receiver receiver)
{
this. receiver = receiver;
}
abstract public void Execute();
}
class ConcreteCommand : Command
{
public ConcreteCommand(Receiver receiver) : base(recover)
{ }
public override void Execute()
{
receiver.Action();
}
}
Invoker类
class Invoker
{
private Command command;
public void SetCommand(Command command)
{
this.command = command;
}
public void ExecuteCommand()
{
command.Execute();
}
}
客户端代码
static void Main(string[] args)
{
Receiver r = new Receiver();
Command c = new ConcreteCommand(r);
Invoker i = new Invoker();
i. SetCommand(c);
i. ExecuteCommand();
Console.Read();
}