命令模式18

一、定义

        将一个请求(命令)封装为一个对象。这个请求(命令)定义了“谁去做”与“做什么”。

        命令模式的例子牢牢记住“电视机遥控器”就可以了。

Invoker通过Command,最终让Receiver接受者执行。

Invoker.action(); ==>  command.execute(); ==> receiver.action();

        

        

        接收者(Receiver)角色:具体的去执行一个请求。它只负责完成自己的职责,不关心谁去命令它。

        命令(Command)角色:一个抽象的命令。命令 = Receiver+ 做什么。将“接收者”与“做什么”都抽象出来。

        具体命令(ConcreteCommand)角色:负责接收具体的接收者,并且实现“做什么”,一般让接收者去完成任务。

        请求者(Invoker)角色:请求者发布相关命令,发布命令的时候要求得到命令的执行结果,不关心执行的过程。这个结果通过command角色的“做什么”方法得到。

        推荐文章:码农小汪-设计模式之-命令模式

                        《JAVA与模式》26天系列—第21天—命令模式

二、优缺点

        优点:    

        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

 

 

 

 

 

posted @ 2022-07-17 12:15  小大宇  阅读(19)  评论(0编辑  收藏  举报