问题
我的电脑城的有多个销售经理,有一个配件管理员。之前的模式是销售经理接待客户,客户提出需求,销售经理告诉配件管理员,例如三星1t固态硬盘一个,罗技键盘一个等等。配件管理员记录之后,从仓库拿出配件,再交付给对应客户。这样就出了个问题,在忙的时候,一个管理员需要对多个销售经理,然后需求不同,记录并取货,还有的时候,客户定下来之后又后悔了,不要了或者想换个别的,管理员就被销售经理给折腾疯了,根本不知道哪些是需要的,哪些是不需要的,还经常拿错了配件给到客户。这样下去可不行啊,乱糟糟的流程导致员工们经常出错。这就需要我们今天的主题——命令模式了。
简介
命令模式如何解决这个问题呢?首先销售经理不能一个配件一个配件的告知管理员,而是根据客户需要把需要的配件列成清单,管理员只接收清单的任务,根据清单拿对应的配件。顾客取消清单,则有销售经理告知xx清单取消即可。就非常简洁得解决了这个问题。其核心思想就是将客户需求转为一条包含所有需求的命令,可以对这个命令延迟执行,撤销,恢复等操作。这个其实也可以类比于饭店厨师做菜,开始生意少的时候,顾客点菜后,服务端都是高喊一声鱼香肉丝一份,宫保鸡丁一份等等,厨师听到后开始做菜,后来生意好了之后,厨师忙不过来,根本听不到服务员喊的菜名。这时候,服务员就会记录下顾客的做菜需求,然后将清单给到厨房,厨房拿到做菜清单之后,将其放在菜单队列,依序取出菜单进行做菜。我们来看看如何实现吧。
实现
Command抽象类
public abstract class Command {
/**
* 模拟顾客的需求
*/
protected String info;
abstract void execute();
}
具体的命令类
public class CacheCommand extends Command {
public CacheCommand(String info) {
this.info = info;
}
@Override
void execute() {
System.out.println("buy cache: " + info);
}
}
public class DiskCommand extends Command{
public DiskCommand(String info) {
this.info = info;
}
@Override
void execute() {
System.out.println("buy disk: " + info);
}
}
public class KeyboardCommand extends Command{
public KeyboardCommand(String info) {
this.info = info;
}
@Override
void execute() {
System.out.println("buy keyboard: " + info);
}
}
销售经理
public class Salesman {
public Salesman(Keeper keeper) {
this.keeper = keeper;
commandList = new LinkedList<>();
}
private Keeper keeper;
private Queue<Command> commandList;
public void addCommand(Command command) {
commandList.add(command);
}
public void cancelCommand(Command command) {
System.out.println("顾客取消: " + command.info);
commandList.remove(command);
}
public void execute() {
System.out.println("顾客下单,通知管理员取配件");
for (Command command : commandList) {
keeper.execute(command);
}
}
}
管理员
public class Keeper {
public void execute(Command command) {
command.execute();
}
}
执行
public static void main(String[] args) {
CacheCommand cacheCommand = new CacheCommand("8G");
DiskCommand diskCommand = new DiskCommand("1T SSD");
KeyboardCommand keyboardCommand = new KeyboardCommand("luoji");
Keeper keeper = new Keeper();
Salesman salesman = new Salesman(keeper);
salesman.addCommand(cacheCommand);
salesman.addCommand(diskCommand);
salesman.addCommand(keyboardCommand);
salesman.execute();
salesman.cancelCommand(diskCommand);
salesman.execute();
}
执行结果
顾客下单,通知管理员取配件
buy cache: 8G
buy disk: 1T SSD
buy keyboard: luoji
顾客取消: 1T SSD
顾客下单,通知管理员取配件
buy cache: 8G
buy keyboard: luoji
总结
总结上面的代码,顾客有三个需求,分别是8G的内存,1T的SSD和罗技的键盘,销售经理将其封装成三个命令,列在清单上,当顾客确定下单后,销售经理就通知管理员根据清单上的内容拿对应的配件即可。当然在下单之前,顾客取消了硬盘的需求,那么就从订单清单中移出。
命令模式的作用是将请求方和执行方进行解耦:例如顾客和配件管理员之间增加销售经理,顾客和厨师之间增加服务员。将请求转成独立对象:顾客需要某某品牌的机械键盘,颜色要求,轴距要求等等信息可以封装成独立对象,给到执行方,更加清晰明了。支持撤销操作
优点:开闭原则:轻松增加新的命令;单一职责:每个命令只完成自己的职责;可实现撤销和恢复操作;解耦
缺点:解耦产生的缺点也就是增加了系统的复杂性,命令过多的话,会添加较多的实现类。
命令模式从理解上来说相对晦涩一些。首先命令模式解放了执行者,执行者只专注于执行,接受到命令,执行即可。其他操作由中间者完成(很多设计模式均有类似思想)。