命令模式-Command Pattern
命令模式是一种数据驱动的设计模式,它属于行为型模式。请求以命令的形式包裹在对象中,并传给调用对象。调用对象寻找可以处理该命令的合适的对象,并把该命令传给相应的对象,该对象执行命令。
一、类图
经典的命令模式包括如下4个角色:
- Command:定义命令的统一接口
- ConcreteCommand:Command接口的实现者,用来执行具体的命令,某些情况下可以直接用来充当Receiver。
- Receiver:命令的实际执行者
- Invoker:命令的请求者,是命令模式中最重要的角色。这个角色用来对各个命令进行控制。
二、示例
电视机是请求的接收者,遥控器是请求的发送者,遥控器上有一些按钮,不同的按钮对应电视机的不同操作。抽象命令角色由一个命令接口来扮演,有三个具体的命令类实现了抽象命令接口,这三个具体命令类分别代表三种操作:打开电视机、关闭电视机和切换频道。显然,电视机遥控器就是一个典型的命令模式应用实例。
抽象命令类:
public interface AbstractCommand{ public void execute(); }
具体的命令类:换台
public class TVChangeCommand implements AbstractCommand{ private Television tv; public TVChangeCommand(){ tv = new Television(); } public void execute(){ tv.changeChannel(); } }
具体的命令类:关机
public class TVCloseCommand implements AbstractCommand{ private Television tv; public TVCloseCommand(){ tv = new Television(); } public void execute(){ tv.close(); } }
具体的命令类:开机
public class TVOpenCommand implements AbstractCommand{ private Television tv; public TVOpenCommand(){ tv = new Television(); } public void execute(){ tv.open(); } }
接收者类
public class Television{ public void open(){ System.out.println("打开电视机!"); } public void close() { System.out.println("关闭电视机!"); } public void changeChannel() { System.out.println("切换电视频道!"); } }
调用者(Invoker)类
public class Controller { private AbstractCommand openCommand, closeCommand, changeCommand; public Controller(AbstractCommand openCommand, AbstractCommand closeCommand, AbstractCommand changeCommand) { this.openCommand = openCommand; this.closeCommand = closeCommand; this.changeCommand = changeCommand; } public void open() { openCommand.execute(); } public void change() { changeCommand.execute(); } public void close() { closeCommand.execute(); } }
三、优缺点
优点
每个命令都被封装起来,对于客户端来说,需要什么功能就去调用相应的命令,而无需知道命令具体是怎么执行的。比如有一组文件操作的命令:新建文件、复制文件、删除文件。如果把这三个操作都封装成一个命令类,客户端只需要知道有这三个命令类即可,至于命令类中封装好的逻辑,客户端则无需知道。
其次,命令模式的扩展性很好,在命令模式中,在接收者类中一般会对操作进行最基本的封装,命令类则通过对这些基本的操作进行二次封装,当增加新命令的时候,对命令类的编写一般不是从零开始的,有大量的接收者类可供调用,也有大量的命令类可供调用,代码的复用性很好。比如,文件的操作中,我们需要增加一个剪切文件的命令,则只需要把复制文件和删除文件这两个命令组合一下就行了,非常方便。
缺点
命令模式的缺点就是命令如果很多,开发起来就要头疼了。特别是很多简单的命令,实现起来就几行代码的事,而使用命令模式的话,不用管命令多简单,都需要写一个命令类来封装。
四、Tomcat中命令模式
Tomcat中Connector 也是通过命令模式调用 Container。Connector 作为抽象请求者,HttpConnector 作为具体请求者。HttpProcessor 作为命令。Container 作为命令的抽象接受者,ContainerBase 作为具体的接受者。客户端就是应用服务器 Server 组件了。Server 首先创建命令请求者 HttpConnector 对象,然后创建命令 HttpProcessor 命令对象。再把命令对象交给命令接受者 ContainerBase 容器来处理命令。命令的最终是被 Tomcat 的 Container 执行的。命令可以以队列的方式进来,Container 也可以以不同的方式来处理请求,如 HTTP1.0 协议和 HTTP1.1 的处理方式就会不同。
……更多设计模式的内容,可以访问Refactoring.Guru