命令模式18
一、定义
将一个请求(命令)封装为一个对象。这个请求(命令)定义了“谁去做”与“做什么”。
命令模式的例子牢牢记住“电视机遥控器”就可以了。
Invoker通过Command,最终让Receiver接受者执行。
Invoker.action(); ==> command.execute(); ==> receiver.action();
接收者(Receiver)角色:具体的去执行一个请求。它只负责完成自己的职责,不关心谁去命令它。
命令(Command)角色:一个抽象的命令。命令 = Receiver+ 做什么。将“接收者”与“做什么”都抽象出来。
具体命令(ConcreteCommand)角色:负责接收具体的接收者,并且实现“做什么”,一般让接收者去完成任务。
请求者(Invoker)角色:请求者发布相关命令,发布命令的时候要求得到命令的执行结果,不关心执行的过程。这个结果通过command角色的“做什么”方法得到。
推荐文章:码农小汪-设计模式之-命令模式
二、优缺点
优点:
1.解耦了命令请求者与接收者之间的关系。
2.新命令容易添加到系统中,不影响其它具体命令,符合开放闭合原则。
3.容易设计出命令队列,将多个命令放入一个集合中,依次执行,动态撤销。
4.可以动态的撤销命令,将命令从队列中移除。
缺点:
1.系统将会多出很多具体的命令类。
2.另外,一般命令队列是一个集合,为了能够支持撤销,需要队列有“安全失败”的能力。java.util.concurrent包下的容器都是安全失败,可以在多线程下并发使用,并发修改。因此,多线程的引入必然降低了一些系统性能。
三、心法
1.职责分离。命令模式的本质是对命令进行封装,将发出命令的责任和执行命令的责任分割开。
2.解耦。请求一方与接收一方完全独立。请求者生成Command命令并得到结果,Command决定谁去做与做什么。
3.动态切换。命令模式使请求本身成为一个对象,这个对象和其他对象一样可以被存储和传递。因此,命令对象可以使用其它设计模式,比如为当前系统预设计多个命令对象,使用策略设计模式动态的切换。
4.动态撤销。因为命令被视为对象,可以把命令对象放入队列集合中,可以根据实际情况将一些撤销掉的命令移出命令队列。当然了,这个时候往往就扯到了线程安全还有快速失败等。
5.组装命令。命令模式是将功能提升到对象来操作,以便对多个功能进行一系列的处理以及封装。遥控器的例子。我们与电视之间并不直接交互,但是遥控器封装了大量的功能,我们才能方便的看电视。
四、例子
下午在学习工作流中,查看源码,发现Activity框架,大量使用了命令设计模式,直接上源码,不多BB。
package org.activiti.engine;
public interface RepositoryService {
DeploymentBuilder createDeployment();
void deleteDeployment(String var1);
/** @deprecated */
void deleteDeploymentCascade(String var1);
void deleteDeployment(String var1, boolean var2);
void setDeploymentCategory(String var1, String var2);
List<String> getDeploymentResourceNames(String var1);
InputStream getResourceAsStream(String var1, String var2);
本实现类就是实实在在的调用环境,那么就可以视为客户端。因此RepositoryServiceImpl这个类可以看成client,它持有commandExcutor的引用。
commandExcutor,它拥有一个叫execute方法,这个方法上的参数就是命令Command。因此,commandExcutor可以视为Invoker,视为发布命令的人。
commandExcutor是发布命令的人,发布的方法叫做execute。execute方法的参数,是一个叫Command接口的实现类。本例子中传递的都是Command接口的实现类,deleteDeploymentCmd对象。
Command的实现类构造函数上接收的参数,比如deploymentId,是接收者。只不过这个接收者并不是Java中实实在在的对象,实际上可以视为数据库中的某条记录。熟悉Activity工作流的同事应该知道,操作的是act_re_deployment表中的某个部署的任务。如图所示。deleteDeployment其实就是要删除图中的某个id的记录。
package org.activiti.engine.impl;
import java.io.InputStream;
import org.activiti.validation.ValidationError;
public class RepositoryServiceImpl extends ServiceImpl implements RepositoryService {
public RepositoryServiceImpl() {
}
public DeploymentBuilder createDeployment() {
return new DeploymentBuilderImpl(this);
}
public void deleteDeployment(String deploymentId) {
this.commandExecutor.execute(new DeleteDeploymentCmd(deploymentId, false));
}
public void deleteDeploymentCascade(String deploymentId) {
this.commandExecutor.execute(new DeleteDeploymentCmd(deploymentId, true));
}
分割线--------------------------------------------------------------------------------------------
下一篇:备忘录模式19