将命令封装成一个对象, 由调用者执行
优点
- 类间解耦:
调用者角色与接收者角色之间没有任何依赖关系,
调用者实现功能时只需调用Command 抽象类的execute方法就可以,
不需要了解到底是哪个接收者执行。- 可扩展性:
Command的子类可以非常容易地扩展,
而调用者Invoker和高层次的模块Client不产生严 重的代码耦合。- 命令模式结合其他模式会更优秀:
命令模式可以结合责任链模式,实现命令族解析任务;
结合模板方法模式,则可以减少 Command子类的膨胀问题。缺点
- 如果有N个命令,问题就出来 了,
Command的子类就可不是几个,而是N个,
这个类膨胀得非常大。
/**
* 订单信息, 可以添加多个
*/
class Order {
// 订单编号,模拟单号递增
int orderNum;
// 订单容器, 存放订单名称和数量
Map<String, Integer> orders = new HashMap<>();
public void setFood(String foodName, int count) {
orderNum++;
orders.put(foodName, count);
}
}
Receiver类,知道如何实施与执行一个与请求相关的操作,任何类都可能作为一个接受者
/**
* 厨师信息, 提供出餐方法
*/
class Chef {
void makeFood(String orderName, int number) {
System.out.printf("厨师制作 %d份 %s %n", number, orderName);
}
}
Command类,用来声明执行操作的接口
/**
* 命令接口
*/
interface Command {
void execute();
}
/**
* 核心类, 聚合厨师和订单信息
*/
class CommandImpl implements Command {
Chef chef;
Order order;
public CommandImpl(Chef chef, Order order) {
this.chef = chef;
this.order = order;
}
@Override
public void execute() {
System.out.println("CommandImpl before current 共" + order.orderNum + "单");
Map<String, Integer> orders = order.orders;
Set<String> keySet = orders.keySet();
for (String food : keySet) {
chef.makeFood(food, orders.get(food));
}
System.out.println("CommandImpl after");
}
}
Execute
/**
* 服务员, 专注于执行命令
*/
class Waiter {
List<Command> commands = new ArrayList<>();
public void setCommands(Command command) {
this.commands.add(command);
}
public void sendCommand() {
for (Command command : commands) {
if (command != null) {
command.execute();
}
}
}
}
Run
@Test
public void client() {
// 创建订单
Order order = new Order();
order.setFood("炒拉条", 2);
order.setFood("果汁", 1);
order.setFood("可乐", 1);
// 创建厨师
Chef john = new Chef();
// 通过订单和厨师信息构建出命令对象
Command command = (Command) new CommandImpl(john, order);
// 执行命令
Waiter amy = new Waiter();
amy.setCommands(command);
amy.sendCommand();
}
CommandImpl before current 共3单
厨师制作 2份 炒拉条
厨师制作 1份 果汁
厨师制作 1份 可乐