命令模式-请求发送者与接收者解耦

 去小餐馆吃饭的时候,顾客直接跟厨师说想要吃什么菜,然后厨师再开始炒菜。去大点的餐馆吃饭时,我们是跟服务员说想吃什么菜,然后服务员把这信息传到厨房,厨师根据这些订单信息炒菜。为什么大餐馆不省去这个步骤,像小餐管那样点菜呢?原因主要有以下几点:

  1. 提供效率。厨师专注炒菜就行,而不必花时间跟客户接触。
  2. 各司其职,提高服务质量。厨师擅长炒菜,而服务员擅长跟顾客打交道。
  3. 使工作有条不紊的进行。不会像小餐馆那样,来了个新客户,需要马上停止炒菜,去招呼客人,而另一边客户要在催着上菜。
  4. 阻断客户与厨师的接触。客户无须知道炒菜的厨师是谁,厨师也不需要知道他为谁炒的菜。

在这里,服务员发挥着“命令”的作用,将客户的命令传递给厨师,厨师做出相应。而这种模式是一种“命令模式”。

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 优缺点

优点:

  1. 降低系统的耦合度,请求者与接收者之间完全解耦,相同的请求者可对应不同的接收者。同样,相同的接收者也也可以供不同的请求者使用,两者具有良好的独立性。
  2. 新的命令可用很容易地加入系统中。增加新的具体命令不会影响其他类,符合开闭原则。
  3. 笔记容易设计一个命令队列或宏命令。
  4. 为请求的撤销和恢复操作提供了一种设计和实现方案。

缺点:

1)会导致系统有过多的具体命令类。

3 适用场景

  1. 需要将请求调用者和请求接收者解耦。
  2. 系统需要支持命令的撤销和恢复操作。
  3. 需要将一组操作组合在一起形成宏命令。
  4. 需要在不同的时间指定请求、将请求排队和执行请求。一个命令对象和请求的初始调用者可以有不同的生命期。即最初的请求发出者可能已经不在了,而命令对象本身仍然是活动的。可以通过该命令对象去调用请求接收者,而无须关系请求调用者的存在性,可以通过请求日志等机制来具体实现。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值