去小餐馆吃饭的时候,顾客直接跟厨师说想要吃什么菜,然后厨师再开始炒菜。去大点的餐馆吃饭时,我们是跟服务员说想吃什么菜,然后服务员把这信息传到厨房,厨师根据这些订单信息炒菜。为什么大餐馆不省去这个步骤,像小餐管那样点菜呢?原因主要有以下几点:
- 提供效率。厨师专注炒菜就行,而不必花时间跟客户接触。
- 各司其职,提高服务质量。厨师擅长炒菜,而服务员擅长跟顾客打交道。
- 使工作有条不紊的进行。不会像小餐馆那样,来了个新客户,需要马上停止炒菜,去招呼客人,而另一边客户要在催着上菜。
- 阻断客户与厨师的接触。客户无须知道炒菜的厨师是谁,厨师也不需要知道他为谁炒的菜。
在这里,服务员发挥着“命令”的作用,将客户的命令传递给厨师,厨师做出相应。而这种模式是一种“命令模式”。
1 命令模式概述
引入一个命令类,通过命令类来降低发送者和接收者的耦合度。将一个请求封装成一个命令对象,发送者只需指定一个命令对象,再通过命令对象来调用请求接收者的处理方法。
图 命令模式结构图
Command:抽象命令类,一般是抽象类或接口。声明了用于执行请求的execute()等方法,通过这些方法可调用请求接收者相关操作。
ConcreteCommand:具体命令类,对应具体接收者对象,维护了一个接收者对象的引用,在实现execute()方法时,将调用接收者对象的相关操作(action()方法等)。
Invoker:调用者,即请求发送者。通过命令对象来执行请求。
Reciver:接收者,执行与请求相关的操作,具体实现对请求的业务处理。
public interface Command {
String getName();
void makeOrder(String name);
}
public class WaiterCommand implements Command{
private final String name;
private CookReceiver cookReceiver;
public WaiterCommand(String name, CookReceiver cookReceiver) {
this.name = name;
this.cookReceiver = cookReceiver;
}
public void setCookReceiver(CookReceiver cookReceiver) {
this.cookReceiver = cookReceiver;
}
@Override
public String getName() {
return name;
}
@Override
public void makeOrder(String name) {
System.out.print(" " + cookReceiver.getName() + ":");
cookReceiver.cooking(name);
}
}
public class CookReceiver {
private final String name;
public CookReceiver(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void cooking(String name) {
System.out.println("开始做菜:" + name);
}
}
public class CustomerInvoker {
private Command waiter;
public CustomerInvoker(Command waiter) {
this.waiter = waiter;
}
public void changeWaiter(Command waiter) {
this.waiter = waiter;
}
public void makeOrder(String name) {
System.out.print(waiter.getName() + "为客户下单");
waiter.makeOrder(name);
}
}
public class Client {
private final static List<Command> waiterList = new ArrayList<>();
static {
CookReceiver cook1 = new CookReceiver("黄师傅");
CookReceiver cook2 = new CookReceiver("刘师傅");
waiterList.add(new WaiterCommand("小李",cook1));
waiterList.add(new WaiterCommand("小张",cook2));
waiterList.add(new WaiterCommand("小王", cook1));
}
public static void main(String[] args) {
String[] menu = {"辣椒炒肉","剁椒鱼头","清蒸豆腐","爆炒花甲","酸辣螺蛳粉"};
Random random = new Random();
for (int i = 0; i < 6; i++) {
CustomerInvoker invoker = new CustomerInvoker(waiterList.get(random.nextInt( waiterList.size())));
invoker.makeOrder(menu[random.nextInt(menu.length)]);
System.out.println("--------------");
}
// 运行结果:
// 小王为客户下单 黄师傅:开始做菜:酸辣螺蛳粉
// --------------
// 小王为客户下单 黄师傅:开始做菜:辣椒炒肉
// --------------
// 小张为客户下单 刘师傅:开始做菜:剁椒鱼头
// --------------
// 小张为客户下单 刘师傅:开始做菜:爆炒花甲
// --------------
// 小王为客户下单 黄师傅:开始做菜:辣椒炒肉
// --------------
// 小王为客户下单 黄师傅:开始做菜:酸辣螺蛳粉
// --------------
}
}
命令模式的本质是对请求进行封装,一个请求对应一个命令。将发送命令与执行命令分割开,但不能减少类的数量。
1.1 命令队列
一个请求发送者发送一个请求时,不止一个请求接收者产生响应,这些接收者将逐个执行业务方法,完成对请求的处理。
图 命令队列结构图
2 优缺点
优点:
- 降低系统的耦合度,请求者与接收者之间完全解耦,相同的请求者可对应不同的接收者。同样,相同的接收者也也可以供不同的请求者使用,两者具有良好的独立性。
- 新的命令可用很容易地加入系统中。增加新的具体命令不会影响其他类,符合开闭原则。
- 笔记容易设计一个命令队列或宏命令。
- 为请求的撤销和恢复操作提供了一种设计和实现方案。
缺点:文章来源:https://www.toymoban.com/news/detail-627302.html
1)会导致系统有过多的具体命令类。文章来源地址https://www.toymoban.com/news/detail-627302.html
3 适用场景
- 需要将请求调用者和请求接收者解耦。
- 系统需要支持命令的撤销和恢复操作。
- 需要将一组操作组合在一起形成宏命令。
- 需要在不同的时间指定请求、将请求排队和执行请求。一个命令对象和请求的初始调用者可以有不同的生命期。即最初的请求发出者可能已经不在了,而命令对象本身仍然是活动的。可以通过该命令对象去调用请求接收者,而无须关系请求调用者的存在性,可以通过请求日志等机制来具体实现。
到了这里,关于命令模式-请求发送者与接收者解耦的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!