命令模式(Command)
1、概述
命令模式由三部分构成:Invoker(命令触发器)、Executor(命令处理器)、Responder(命令响应器)。命令模式将客户端(也就是这里的Invoker命令触发器)与服务端(Responder命令响应器)两者解耦。客户端只需要关注自己发送哪一条命令,而无需关注服务端的实现细节;服务端只需关注命令是什么,根据命令作出相应响应,而无需与客户端建立直接联系。命令模式中的Executor如同电脑中的中央处理器(Central Processing Unit),用于处理各式各样的请求。
2、产生背景
有人可能会质疑:不要Executor,客户端和服务端依然可以交互啊?
诚然,即使没有Executor,客户端和服务端依然可以交互,但前提是客户端知晓服务端能够接受的命令以及对接受的命令作出相应的相应的情况下才能顺利完成交互。这样想固然没有错误,但命令模式存在,就有它存在的合理性。
现在抛出一个场景:假设你自己就是客户端,你现在需要打开“腾讯QQ.exe”这一应用程序,你怎么打开?有两种打开方式:
- 直接双击图标
- 通过命令行输入命令
答案显而易见。对于绝大多数用户,都会选择第一种方式打开;对于极少数喜欢作死的,就会选择第二种。有人会说:“这两种方式本质上不一样。”。这两种方式本质上是一样的,直接双击图标的操作还是会通过命令执行,不同的就是第一种背后有内部的Executor替你编译命令了并转发了“双击图标——腾讯QQ”这一“命令”,第二种就没有Executor,相当原始的操作。相信大家阅读到这里,应该理解到了Executor这一中间件的重要性。
相信大家都多多少少学过MVC框架。市面上流行的MVC框架有SpringMVC、Struts2。大家还记得StrutsPrepareAndExecutorFilter这个类吗?这就是利用了命令模式。StrutsPrepareAndExecutorFilter相当于命令模式中的中间件——Executor,属于Controller层的模块。大家还记得DispatcherServlet这个类吗?也用到了命令模式,同样属于Controller层。
3、实例分析
一个简单的CRUD模拟应用,直接上代码。
/**
* @author Hanlin Wang
*/
public class CommandMode {
public static void main(String[] args) {
//发出命令
Invoker.send("add");
Invoker.send("remove");
Invoker.send("set");
Invoker.send("get");
Invoker.send("haha");
//结果
/*add() method has been invoked
remove() method has been invoked
set() method has been invoked
get() method has been invoked
unknown method*/
}
}
//定义调用器
class Invoker{
public static void send(String command){
Executor.execute(command);
}
}
//定义执行器,模仿Struts2中的StrutsPrepareAndExecuteFilter
class Executor{
public static void execute(String command){
switch (command) {
case "add":
Responder.add();
break;
case "remove":
Responder.remove();
break;
case "set":
Responder.set();
break;
case "get":
Responder.get();
break;
default:
System.out.println("unknown method");
break;
}
}
}
//定义响应器
class Responder{
public static void add(){
System.out.println("add() method has been invoked");
}
public static void remove(){
System.out.println("remove() method has been invoked");
}
public static void set(){
System.out.println("set() method has been invoked");
}
public static void get(){
System.out.println("get() method has been invoked");
}
}