设计模式之命令模式

377 阅读4分钟

       操作数据库时有各种操作,即有插入,删除,又有更新。各种操作间,其实可以看成我们给数据库发送命令,让它根据我们的命令执行相应的操作。操作模式中的命令模式恰好可以很好的封装命令。我们并不需要数据库做了什么具体的操作,我们需要的就是发出一个命令,之后数据库按照我们的命令做相应的操作。

一、定义

定义(来源:维基百科)Command pattern)是一种设计模式,它尝试以命令來代表实际操作。命令类可以把行动(action) 及其参数封装起來,于是這些行动可以被:重复多次、取消后又重做

看了百度百科的定义,感觉不是太好理解,于是我把维基百科的定义重新修饰了一下。

要点解析:

1、通过命令来表示实际的操作。我们平时写代码基本就是需要什么功能,则直接调用某方法,而命令模式是通过发送一个命令的方式。

2、命令在执行前是可以被取消、或者重复执行同一个命令的。

看了定义可能你还云里雾里的,不是特别清楚命令模式是怎么回事?别急,你现在只要清楚:1客户端通过发送命令来做具体的操作。2、操作执行前是可以取消掉的。

二、UML

先来看看命令模式下,都涉及到哪些角色:

1、首先必须有命令类,于是我们需要一个命令的抽象类、如下图中的Command类。

2、其次,需要有具体的命令类,你到底是请求删数据呢,还是新增数据呢?你得定义删除,新增的命令,如下图中的InsertCommand、DeleteCommand、UpdateCommand。

3、需要有个类来接收客户端发送过来的命令,管理这些命令,因为这些命令还需要可以撤销。下图中的Invoke。

4、发送命令过来的本质还是执行命令代表的具体逻辑,所以还需要有个地方实现这些逻辑,这个角色如下图的Receiver类,实现具体逻辑



三、代码实现

接下来看看数据库操作场景下,命令模式的实现例子

(一)、定义命令的抽象类

package com.design.command;

public abstract class Command {
    //持有具体逻辑操作的引用
    protected Receiver receiver;

    public Command(Receiver receiver) {
        this.receiver = receiver;
    }
    //执行命令的具体逻辑
    public abstract void execute();
}

(二)、具体的命令

package com.design.command;

/**
 * 插入命令
 */
public class InsertCommand extends Command {
    //要插入到数据库的数据
    private String dat;
    public InsertCommand(Receiver receiver) {
        super(receiver);
    }
    //执行插入操作
    @Override
    public void execute() {
        receiver.insertData(dat);
    }

    public String getDat() {
        return dat;
    }

    public void setDat(String dat) {
        this.dat = dat;
    }
}

package com.design.command;

/**
 * 删除命令
 */
public class DeleteCommand extends Command {
    //要删除数据库的数据
    private String dat;

    public DeleteCommand(Receiver receiver) {
        super(receiver);
    }

    @Override
    public void execute() {
        super.receiver.deleteData(dat);
    }

    public String getDat() {
        return dat;
    }

    public void setDat(String dat) {
        this.dat = dat;
    }
}

package com.design.command;

/**
 * 更新命令
 */
public class UpdateCommand extends Command {

    private String dat;

    public UpdateCommand(Receiver receiver) {
        super(receiver);
    }

    @Override
    public void execute() {
        receiver.updateData(dat);
    }

    public String getDat() {
        return dat;
    }

    public void setDat(String dat) {
        this.dat = dat;
    }
}

(三)、具体实现功能的类

package com.design.command;

public class Receiver {

    /**
     *实现插入指令的功能
     * @param data
     */
    public void insertData(String data){
        System.out.println("插入数据库数据:"+data);
    };

    /**
     *实现删除指令的功能
     * @param data
     */
    public void deleteData(String data){
        System.out.println("删除数据库数据:"+data);
    };

    /**
     *实现更新指令的功能
     * @param data
     */
    public void updateData(String data){
        System.out.println("更新数据库数据:"+data);
    };
}

(四)、Invoke类,对接客户端,接收客户端发来的命令

package com.design.command;

import java.util.ArrayList;
import java.util.List;

public class Invoker {
    //通过一个ArrayList来存储客户端发送过来的命令
    private List<Command> commandList = new ArrayList<>();
    //增加命令
    public void addCommand(Command command){
        this.commandList.add(command);
    }
    //取消命令
    public void cancelCommand(Command command){
        this.commandList.remove(command);
    }
   //通知全部命令
    public void executeAllCommand(){
        for (Command command : commandList){
            command.execute();
        }
        commandList.clear();
    }

}

(五)、看看怎么来调用

package com.design.command;

public class TestMain {

    public static void main(String[] args) {
        Receiver receiver = new Receiver();
        //创建插入指令
        InsertCommand insertCmand = new InsertCommand(receiver);
        insertCmand.setDat("用户名为:zhangsan");
        //创建删除指令
        DeleteCommand delCmand = new DeleteCommand(receiver);
        delCmand.setDat("用户名为:lisi");
        //创建更新指令
        UpdateCommand updateCamd = new UpdateCommand(receiver);
        updateCamd.setDat("更新zhangsan用户名为王五");

        Invoker invoker = new Invoker();
        //发送插入指令
        invoker.addCommand(insertCmand);
        //发送删除指令
        invoker.addCommand(delCmand);
        //取消删除指令
        invoker.cancelCommand(delCmand);
        //发送更新指令
        invoker.addCommand(updateCamd);
        //执行所有指令
        invoker.executeAllCommand();
    }
}

(六)、执行结果


可以看到,我们发送了删除命令,之后我们做了取消命令的操作,所以最后并没有执行取消操作,只执行了插入和更新操作。

四、结论

到此,命令模式的说明还有例子都已经呈现。做个总结:命令模式的作用其实就是将以前直接调用逻辑换成通过发送命令的方法,这个可以让我们客户端根具体的逻辑之间进行解耦。其次可轻松实现命令的记录,还有命令的取消、命令的重复等操作。

(一)、优点

1、如上表述、可解耦客户端与具体逻辑。

2、可方便对执行的操作进行记录,如我们可以在Invoke类中对执行的命令进行记录。

3、扩展性好,新增命令简单,只需新增加具体命令类。

4、可进行命令撤销,重复执行命令等。

(二)、缺点

1、可能会造成具体的命令类过多。