命令模式
日常工作中,我们会经常需要向某些对象发送请求,但是并不知道请求的处理者是谁,我们只需要将请求扔给指定的接收者皆可,这个“中介”则会将请求分给对应的请求处理者。这种行为就是一种命令模式。
其实在生活中,我们身边就有很多的命令模式的例子。设想,你去吃饭的时候,点菜、催单、结账,并不是去直接找厨师或者收银员吧。而是中间存在一个“中介”---服务员,你只需要给服务员发出点菜、催单或结账的命令,服务员就会将你的命令传给特定的处理人---厨师或者收银员。
通过上述描述可以看到,命名模式中存在以下几种角色:
- Command:抽象命令类。因为我们的命令并不是一个,而是多个,可以实现同一个抽象命令类
- ConcreteCommand:具体命令类,例如:点菜、催单这就是具体的命令
- Invoker:调用者,服务员就是具体命令的调用者
- Receiver:命令接收者,厨师、收银员就是不同命令的接收者
- Client:客户端,顾客就是客户端,给Invoker下达命令。
下面我们用代码实现一下之前讲解的示例:
首先:我们定义抽象的命令类 和 具体命令类(点菜、催单、结账3种命令)
public interface ICommand { // 具体的命令去实现执行内容 void executor(String param); } // 点菜命令---交给厨师接收者 public class OrderCommand implements ICommand { @Override public void executor(String param) { // 点菜命令最终是交由厨师处理 new CookerReceiver().order(param); } } // 催单命令---交给厨师接收者 public class UrgeCommand implements ICommand { @Override public void executor(String param) { // 催单命令最终是交由厨师处理 new CookerReceiver().urge(param); } } // 结账命令---交给收银员接收者 public class CheckoutCommand implements ICommand { @Override public void executor(String param) { // 结账命令最终交给收银员 new CheckerReceiver().checker(param); } }
接下来,我们定义命令最终的接收者(厨师和收银员)
public class CookerReceiver { // 厨师接到下单命令的处理动作 public void order(String param) { System.out.println(String.format("有客人点菜:%s,马上做", param)); } // 厨师接到催单命令的处理动作 public void urge(String param) { System.out.println(String.format("有客人催单:%s,快点做,否则没工资了", param)); } } public class CheckerReceiver { // 收银员接到结账命令的处理动作 public void checker(String param) { System.out.println(String.format("您点的菜是:%s,一共消费1888", param)); } }
然后,我们就可以组装命令的调用者---服务员了。服务员需要接收所有的命令。
public class Waiter { private ICommand orderCommand; private ICommand urgeCommand; private ICommand checkoutCommand; public Waiter(ICommand orderCommand, ICommand urgeCommand, ICommand checkoutCommand) { this.orderCommand = orderCommand; this.urgeCommand = urgeCommand; this.checkoutCommand = checkoutCommand; } public void order(String param) { orderCommand.executor(param); } public void urge(String param) { urgeCommand.executor(param); } public void checker(String param) { checkoutCommand.executor(param); } }
最后,顾客就可以进行点菜、催单等操作了
public class Client { public static void main(String[] args) { // 创建命令对象 ICommand orderCmd = new OrderCommand(); ICommand urgeCmd = new UrgeCommand(); ICommand checkoutCmd = new CheckoutCommand(); // 创建命令传输对象---服务员 Waiter waiter = new Waiter(orderCmd, urgeCmd, checkoutCmd); // 下单 waiter.order("锅包肉"); // 等了半天没来,催单 waiter.urge("锅包肉"); // 吃完了结账 waiter.checker("锅包肉"); } }
通过上面的代码,我们发现完全把命令发出者(顾客)和命令处理者(厨师、收银员)完全解耦了。下面总结一下命令模式的优缺点:
优点:
- 命令发出和和命令处理者解耦,降低耦合
- 扩展性比较强,加入新的命令比较容易
缺点:
- 当命令比较多的时候,需要有大量的具体命令类