命令模式
将一个请求封装为一个对象,使发出请求的责任和执行请求的责任分隔开。这样两者之间通过命令对象进行沟通,这样方便将命令对象进行存储、传递、调用、增加与管理。
⭐结构
- 抽象命令角色——定义命令的接口,声明执行的方法
- 具体命令角色——具体的命令,实现命令接口。通常会持有接收者,并调用接收者的功能来完成命令要执行的操作。
- 实现者/接收者角色——接收者,是真正去执行命令的对象。而任何一个类都能成为接收者,只要它能够实现命令要求实现的相应功能
- 调用者/请求者角色——要求命令对象执行请求,通常会持有命令对象,可以持有很多的命令对象。这个是客户端真正出发命令并要求命令执行相应操作的地方,也就是说相当于使用命令对象的入口。
🌰举个例子
例如点餐:
服务员就是调用者角色,由其发起命令
厨师就是接收者角色,执行命令的对象
而点餐命令中包含着订单
具体实现:
我们先创建订单类:
public class Order {
//餐桌号码
private int tableNum;
//用Map来装餐品及份数
private Map<String,Integer> foodDir = new HashMap<String,Integer>();
//getter省略,但setter要重写一下,将菜品名和数量传入
public void setFood(String name, int num) {
foodDir.put(name, num);
}
}
然后我们创建厨师类:
public class SeniorChef {
//做菜
public void makeFood(String name, int num) {
System.out.println(num + "份" + name);
}
}
接下来是抽象命令类:
public interface Command {
void execute();
}
具体命令类,在命令类中定义订单类和厨师类
public class OrderCommand implements Command {
//持有接收者对象
private SeniorChef receiver;
private Order order;
public void execute() {
System.out.println(order.getDiningTable() + "桌的订单:");
Map<String, Integer> foodDir = order.getFoodDir();
//遍历map集合
Set<String> keys = foodDir.keySet();
for(String foodName:keys) {
receiver.makeFood(foodName, foodDir.get(foodName));
}
System.out.println(order.getDiningTable() + "桌的饭准备完毕!");
}
}
服务员类:
public class Waitor {
//持有多个命令对象
private List<Command> commands = new ArrayList<Command>();
public void setCommand(Command cmd) {
//将cmd对象放到命令集合中
commands.add(cmd);
}
//发起命令
public void orderUp() {
System.out.println("服务员:大厨,订单来咯!")
//遍历list集合,执行命令
for(Command command : commands) {
if(command !=null) {
command.execute();
}
}
}
}
我们现在就可以去测试类中点单啦:
先创建一个订单对象
Order order = new Order();
然后进行点单
order.setDiningTable(1);//表示第一桌
order.setFood("西红柿鸡蛋面", 1);//点一份西红柿鸡蛋面
order.setFood("可乐",1);//再来一份可乐吧
有了订单,我们就要创建做菜的厨师了
SenioChef receiver = new SeniorChef();
创建命令类将厨师和订单都传入进去
OrderCommand cmd = new OrderCommand(receiver,order);
这个命令相当于我们点好的单,现在就需要把我们点好的单交给服务员
Waitor invoke = new Waitor();
invoke.setCommand(cmd);
最后就是服务员去下达命令,让厨师做饭
invoke.orderUp();
⭐优缺点
优点:
- 降低系统的耦合度。命令模式能将调用操作的对象与实现该操作的对象解耦
- 增加或删除命令非常方便。采用命令模式增加与删除命令不会影响其他类,它满足“开闭原则”,对扩展比较灵活。
- 可以实现宏命令。命令模式可以与组合模式结合,将多个命令装配成一个组合命令,即宏命令。
- 方便实现Undo和Redo操作。命令模式可以与备忘录模式结合,实现命令的撤销与恢复。
缺点:
- 使用命令模式可能会导致某些系统有过多的具体命令类
- 使系统结构更复杂
⭐适用场景
- 系统需要将请求调用者和请求接收者解耦,使得调用者和接收者不直接交互
- 系统需要在不同的时间指定请求、将请求排队和执行请求
- 系统需要支持命令的撤销操作和恢复操作