設(shè)計(jì)模式之——命令模式

命令模式

命令模式:將一個(gè)請求封裝為一個(gè)對象,從而使你可用不同的請求對客戶進(jìn)行參數(shù)化。可以對請求進(jìn)行排隊(duì)或者記錄請求日志,以及支持可撤銷的操作。命令模式通過這種封裝的方式實(shí)現(xiàn)將請求動(dòng)作者和動(dòng)作執(zhí)行者解耦。

控制小車移動(dòng)

接下來創(chuàng)建一個(gè)需求來用命令模式實(shí)現(xiàn)。
我們有一個(gè)Car對象,它有向前移動(dòng)的方法forward()和向后移動(dòng)的方法backward()的方法?,F(xiàn)在我們要控制小車的移動(dòng),要怎么做呢?

緊耦合設(shè)計(jì)

我們先來看看不使用命令模式的緊耦合設(shè)計(jì)
Car類:

public class Car {
    /**
     * 向前移動(dòng)
     */
    public void forward(){
        System.out.println("向前移動(dòng)");
    }

    /**
     * 向后移動(dòng)
     */
    public void backward(){
        System.out.println("向后移動(dòng)");
    }
}

Client類:

/**
 * 緊耦合客戶端類
 */
public class Client {
    public static void main(String[] args) {
        //創(chuàng)建小車對象
        Car car = new Car();
        //小車向前移動(dòng)
        car.forward();
        //小車向前移動(dòng)
        car.forward();
        //小車向后移動(dòng)
        car.backward();
    }
}
向前移動(dòng)
向前移動(dòng)
向后移動(dòng)

我們可以看到客戶端(Client)與動(dòng)作執(zhí)行者(Car)是緊密耦合的。

松耦合命令模式設(shè)計(jì)

既然想要將請求動(dòng)作者和動(dòng)作執(zhí)行者進(jìn)行解耦,那么我們就設(shè)計(jì)一個(gè)遙控器(RemoteControl)來幫我們傳達(dá)命令,控制小車移動(dòng)。
Car類不變

public class Car {
    /**
     * 向前移動(dòng)
     */
    public void forward(){
        System.out.println("向前移動(dòng)");
    }

    /**
     * 向后移動(dòng)
     */
    public void backward(){
        System.out.println("向后移動(dòng)");
    }
}

Command類

/**
 * 命令接口 所以命令類都要實(shí)現(xiàn)此接口
 */
public interface Command {
    void execute();
}

ForwardCommand類

/**
 * 向前移動(dòng)的命令類
 */
public class ForwardCommand implements Command {

    private Car car;

    /**
     * 接受操作執(zhí)行者
     * @param car
     */
    public ForwardCommand(Car car){
        this.car = car;
    }

    public void execute() {
        car.forward();
    }
}

BackwardCommand類

/**
 * 向后移動(dòng)的命令類
 */
public class BackwardCommand implements Command {

    private Car car;

    /**
     * 接受操作執(zhí)行者
     * @param car
     */
    public BackwardCommand(Car car){
        this.car = car;
    }

    public void execute() {
        car.backward();
    }
}

RemoteControl類

/**
 * 遙控器類
 */
public class RemoteControl {

    private Command command;

    /**
     * 設(shè)置控制命令
     * @param command
     */
    public void setCommand(Command command){
        this.command = command;
    }

    /**
     * 執(zhí)行命令
     */
    public void executeCommand(){
        command.execute();
    }
}

Client類

public class Client {
    public static void main(String[] args) {
        Car car = new Car();
        ForwardCommand forwardCommand = new ForwardCommand(car);
        BackwardCommand backwardCommand = new BackwardCommand(car);

        RemoteControl control = new RemoteControl();
        //設(shè)置向前的命令
        control.setCommand(forwardCommand);
        //執(zhí)行命令
        control.executeCommand();
        control.setCommand(backwardCommand);
        control.executeCommand();
    }
}
向前移動(dòng)
向后移動(dòng)

現(xiàn)在如果我們想讓小車移動(dòng),那么我們就只需要給遙控器傳達(dá)移動(dòng)的命令就行了。小車接收到命令就會(huì)去執(zhí)行對應(yīng)的動(dòng)作。

添加命令隊(duì)列

我們可以把小車需要執(zhí)行的命令一次性的添加進(jìn)去,形成一個(gè)隊(duì)列統(tǒng)一執(zhí)行。
我們需要對代碼稍微調(diào)整一下
RemoteControl類

/**
 * 遙控器類
 */
public class RemoteControl {

    private List<Command> commands = new ArrayList<Command>();

    /**
     * 設(shè)置控制命令
     * @param command
     */
    public void setCommand(Command command){
        commands.add(command);
    }

    /**
     * 執(zhí)行命令
     */
    public void executeCommand(){
        for (Command command : commands) {
            command.execute();
        }
    }
}

遙控器的命令屬性我們采用集合來接受,執(zhí)行時(shí)候循環(huán)調(diào)用command的execute方法。
Client類

public class Client {
    public static void main(String[] args) {
        Car car = new Car();
        ForwardCommand forwardCommand = new ForwardCommand(car);
        BackwardCommand backwardCommand = new BackwardCommand(car);

        RemoteControl control = new RemoteControl();
        //設(shè)置向前和向后的命令
        control.setCommand(forwardCommand);
        control.setCommand(backwardCommand);
        //執(zhí)行命令
        control.executeCommand();
    }
}

Client這邊只要添加多次命令統(tǒng)一執(zhí)行就好了。

添加命令執(zhí)行控制

命令模式可以選擇命令是否執(zhí)行
舉個(gè)例子,雖然我向遙控器傳遞了向后移動(dòng)的命令,但是我們有具體的校驗(yàn)邏輯決定是否執(zhí)行后退命令。

/**
 * 遙控器類
 */
public class RemoteControl {

    private List<Command> commands = new ArrayList<Command>();

    /**
     * 設(shè)置控制命令
     * @param command
     */
    public void setCommand(Command command){
        if(check(command)){
            commands.add(command);
        }
    }

    /**
     * 執(zhí)行命令
     */
    public void executeCommand(){
        for (Command command : commands) {
            command.execute();
        }
    }

   /**
     * 校驗(yàn)方法
     * @return
     */
    private boolean check(Command command){
        //如果是后退命令則忽略
        return !(command instanceof BackwardCommand);
    }
}

UML

總結(jié)

我們可以看到命令模式達(dá)到了將請求動(dòng)作者和動(dòng)作執(zhí)行者進(jìn)行解耦的效果。這樣我們可以比較方便的設(shè)計(jì)一個(gè)命令隊(duì)列,也可以對請求是否執(zhí)行進(jìn)行控制,比如還可以對請求進(jìn)行撤銷、重做操作、記錄執(zhí)行日志等。

個(gè)人博客:https://www.zhaojun.ink

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容