命令模式(java实现)

来源:互联网 发布:小缘 大官人知乎 编辑:程序博客网 时间:2024/06/05 08:19

命令模式

烤肉小摊-紧耦合

//烤肉串者

public class Barbecuer {

public void bakeMutton() {

System.out.println("烤羊肉串");

}

public void bakeChickenWing() {

System.out.println("烤鸡翅");

}

}

public class Demo1 {

public static void main(String[]args) {

Barbecuer boy=new Barbecuer();

boy.bakeMutton();

boy.bakeMutton();

boy.bakeChickenWing();

boy.bakeMutton();

boy.bakeChickenWing();

}

}

问题描述:

由于客户和小摊老板紧耦合,尽管简单,但是容易出错,容易混乱,有许许多多的隐患.这其实就是”行为请求者”和”行为实现者”的紧耦合.我们需要记录哪个人需要几串羊肉串,有没有特殊要求(加辣不加辣),付没付过钱,谁先谁后,这其实都相当于对请求做日志.如果有人需要退钱不买了,或者要求烤肉重烤,这其实就相当于撤销和重做.所以对请求排队或记录请求日志,以及支持可撤销操作等行为时,”行为请求者”,”行为实现者”的紧耦合是不太合适的.

解决办法:

开家门面店,增加服务员类

要知道,不管是烤羊肉串,烤鸡翅,还是烤其它烧烤,这些都是”烤肉串者类”的行为,也就是他的方法,具体怎么做由方法内部实现,我们不用去管它.但是对于服务员类来说,他其实就是根据客户的需要,发个命令,有人要十个烤串,有人要十个鸡翅”,这些都是命令.可以把烤肉串者类的方法,分别写成多个命令类,那么它们就可以被服务员请求了,而且这些命令差不多都是一个样式,于是你可以泛化出一个抽象类,让服务员只管对抽象的命令发号施令就可以了.具体是什么命令,即是烤什么,就让客户去决定吧

烧烤门面店-松耦合

//烤肉串者

public class Barbecuer {

public void bakeMutton() {

System.out.println("烤羊肉串");

}

public void bakeChickenWing() {

System.out.println("烤鸡翅");

}

}

 

public abstract class Command {

protected Barbecuer receiver;

public Command(Barbecuer receiver) {

this.receiver=receiver;

}

public abstract void excuteCommand();

}

public class BakeMuttonCommand extends Command{

public BakeMuttonCommand(Barbecuer receiver) {

super(receiver);

}

@Override

public void excuteCommand() {

receiver.bakeMutton();

}

}public class BakeChickenWingCommand extends Command {

public BakeChickenWingCommand(Barbecuer receiver) {

super(receiver);

}

@Override

public void excuteCommand() {

receiver.bakeChickenWing();

}

}

public class Demo2 {

public static void main(String[]args) {

//门面店事先就找好了烤肉厨师,服务员和烤肉菜单,就等顾客上门

Barbecuer boy=new Barbecuer();

Command bakeMuttonCommand1 =new BakeMuttonCommand(boy);

Command bakeMuttonCommand2 =new BakeMuttonCommand(boy);

BakeChickenWingCommand bakeChickenWingCommand1 =new BakeChickenWingCommand(boy);

Waiter girl=new Waiter();

//服务员根据客户的要求,通知厨房开始制作

girl.setOrder(bakeMuttonCommand1);

girl.inform();

girl.setOrder(bakeMuttonCommand2);

girl.inform();

girl.setOrder(bakeChickenWingCommand1);

girl.inform();

}

}

问题描述:

真实的情况其实并不是用户点一个菜,服务员就通知厨房做一个,应该是点完所有烧烤后,服务员一次通知制作

如果此时鸡翅没了,不应该由客户判断有没有,应该是由服务员或烤肉串者来否决这个请求

客户到底点了哪些烧烤和饮料,这是需要记录日志的,以备收费,也包括后期的统计

④客户完全有可能因为烤的肉串太多而考虑取消一些还没有制作的肉串

public class Waiter2 {

private List<Command>orders=new ArrayList<Command>();

//设置订单

public void setOrder(Command command) {

orders.add(command);

System.out.println("增加订单:"+command.toString()+"  时间:"+new Date().toLocaleString());

}

//取消订单

public void cancel(Command command) {

orders.remove(command);

System.out.println("取消订单"+command.toString()+"  时间:"+new Date().toLocaleString());

}

//通知全部执行

public void inform() {

for (Command command :orders) {

command.excuteCommand();

}

}

}

public class Demo3 {

public static void main(String[]args) {

Barbecuer boy=new Barbecuer();

Command bakeMuttonCommand1 =new BakeMuttonCommand(boy);

Command bakeMuttonCommand2 =new BakeMuttonCommand(boy);

Command bakeChickenWingCommand1 =new BakeChickenWingCommand(boy);

Waiter2 girl=new Waiter2();

//开门营业,顾客点菜

girl.setOrder(bakeMuttonCommand1);

girl.setOrder(bakeMuttonCommand2);

girl.setOrder(bakeChickenWingCommand1);

//点菜完毕,通知厨房

girl.inform();

}

}

输出结果:

增加订单:烤羊肉串命令  时间:2017-11-25 14:59:05

增加订单:烤羊肉串命令  时间:2017-11-25 14:59:05

增加订单:烤鸡翅命令  时间:2017-11-25 14:59:05

烤羊肉串

烤羊肉串

烤鸡翅

命令模式

命令模式:

将一个请求封装成一个对象,从而使你可用不同的请求对客户进行参数化;对请求排队或记录请求日志,以及支持可撤销的操作.

命令模式的优点:

①它能较容易地设置一个命令队列

在需要的情况下,它能较容易地将命令记入日志

③允许接收请求的一方决定是否要否决请求

④可以容易地实现对请求的撤销和重做

由于加进新的具体命令类不影响其他的类,因此增加新的具体命令类很容易

⑥把请求一个操作的对象与知道怎么执行一个操作的对象分隔开

注意:

命令模式支持对请求的撤销和重做,但是你还不清楚是否需要这个功能的时候,你要不要实现命令模式呢?

其实应该是不要实现.敏捷开发原则告诉我们,不要为代码添加基于猜测的,实际不需要的功能.如果不清楚一个系统是否需要命令模式,一般不要急着去实现它,事实上,在需要的时候通过重构实现这个模式并不困难,只有真正需要如撤销/恢复操作功能的时候,把原来的代码重构为命令模式才有意义.

原创粉丝点击