1、定义
将一个请求封装为对象,从而使你可用不同的请求对客户进行参数化;对请求排队或记录请求日志,以及支持可撤销的操作。
2、使用场景
烧烤店烤串,出现三个角色:买串人、服务员、烤肉师傅。
买串人点了5串烤肉,5串烤鸡翅 ,2串土豆,服务员用本子记录当前用户桌号、各类烤串数量,并可以告知买串人此烤串是否有备货,提醒用户取消对应的订单,然后点好菜之后服务员将菜单拿到厨房,交给烧烤师傅,烧烤师傅开始按照菜单分类开烤。
当出现多个不同的买串人下单时都按照此流程进行操作,一切都会变得次序井然。
3、代码结构UML图
顾客:请求发起者。
服务员:又称Invoker ,要求该命令执行这个请求;
命令:用来声明执行操作的接口;
烤肉师傅:知道如何实施与执行一个请求相关的操作,任何类都能作为一个接收者;
烤羊肉串命令、烤鸡翅命令:将一个接收者对象绑定与一个动作,调用接收者相应的操作,以实现Execute。
4、类的实现
(1)Barbecuer (烤肉师傅类)
public class Barbecuer {
//烤羊肉串
public void bakeMutton(){
System.out.println("烤羊肉串!");
}
public void bakeChickenWing(){
System.out.println("烤鸡翅!");
}
}
(2)Command(抽象命令类)
public abstract class Command{
protected Barbecuer receiver;
public Command (Barbecuer receiver){
this.receiver=receiver;
}
//执行命令
abstract public void excuteCommand();
}
(3)BakeMuttonCommand(烤羊肉串命令类)
public class BakeMuttonCommand extends Command{
protected Barbecuer receiver;
public BakeMuttonCommand (Barbecuer receiver){
this.receiver=receiver;
}
//执行命令
public void excuteCommand(){
receiver.bakeMutton();
}
}
(4)BakeChickenWingCommand(烤鸡翅命令类)
public class BakeChickenWingCommand extends Command{
protected Barbecuer receiver;
public BakeChickenWingCommand (Barbecuer receiver){
this.receiver=receiver;
}
//执行命令
public void excuteCommand(){
receiver.bakeChickenWing();
}
}
(5)Waiter(服务员类)
public class Waiter {
private List<Command> orders=new ArrayList<>();
public void setOrder(Command command){
if(command instanceof BakeChickenWingCommand){
System.out.println("服务员:鸡翅没有了,请点别的烧烤。");
}else {
orders.add(command);
System.out.println("增加订单:"+command.toString()+" 时间:"+new SimpleDateFormat("yyyy-MM-dd HH:mm:ss".format(new Date())) );
}
}
public void cancelOrder(Command command){
orders.remove(command);
System.out.println("取消订单:"+command.toString()+" 时间:"+new SimpleDateFormat("yyyy-MM-dd HH:mm:ss".format(new Date())));
}
public void notify(){
foreach(Command cmd:orders){
cmd.excuteCommand();
}
}
}
5、客户端调用
public static void main(String[] args){
//开店前的准备
Barbecuer boy =new Barbecuer();
Command bakeMuttonCommand1=new BakeMuttonCommand(boy);
Command bakeMuttonCommand2=new BakeMuttonCommand(boy);
Command bakeMuttonCommand1=new BakeChickenWingCommand(boy);
Waiter girl=new Waiter();
//开门营业 顾客点菜
girl.setOrder(bakeMuttonCommand1);
girl.setOrder(bakeMuttonCommand2);
girl.setOrder(bakeMuttonCommand1);
//通知厨房开始做菜
girl.notify();
}
6、总结
它能较容易的设计一个命令队列;在需要的情况下,可以较容易的将命令记入日志;允许接受请求的一方觉得是否要否决请求;可以容易的实现对请求的撤销和重做;由于加进新的具体命令类不影响其他的类,因此增加新的具体命名类很容易。
命令模式把请求一个操作的对象与知道怎么执行一个操作的对象分割开。
敏捷开发原则告诉我们,不要为代码添加基于猜测的、实际不需要的功能。如果不清楚一个系统是否需要命令模式,一般就不要着急去实现它,事实上,在需要的时候通过重构实现这个模式并不难,只有真正需要如撤销/恢复操作等功能时,把原来的代码重构为命令模式才有意义。
参考:《大话设计模式》