命令模式實(shí)現(xiàn)undo和redo

命令模式

定義與類型

  • 定義: 命令模式將一個(gè)請(qǐng)求封裝成對(duì)象,讓用戶使用不同的請(qǐng)求將客戶端參數(shù)化。
  • 類型: 行為型

適用場(chǎng)景

  • 想用對(duì)象參數(shù)化一個(gè)動(dòng)作以執(zhí)行操作,并且用不同命令對(duì)象來替換回調(diào)函數(shù)
  • 應(yīng)用程序支持撤銷和恢復(fù)
  • 記錄請(qǐng)求日志,當(dāng)系統(tǒng)故障這些命令可以重新被執(zhí)行

優(yōu)點(diǎn)

  • 能較容易的設(shè)計(jì)一個(gè)命令隊(duì)列
  • 在需要的情況下,可以容易的將命令計(jì)入日志
  • 允許接收請(qǐng)求的一方?jīng)Q定是否否決請(qǐng)求
  • 可以容易的實(shí)現(xiàn)對(duì)請(qǐng)求的撤銷和重做
  • 由于加進(jìn)新的具體命令類不影響其他的類,因此便于擴(kuò)展
  • 命令模式將請(qǐng)求一個(gè)操作的對(duì)象與具體執(zhí)行一個(gè)操作的對(duì)象分割開,符合開閉原則和迪米特法則

缺點(diǎn)

角色劃分

  • 角色一:接收者(Receiver作用:負(fù)責(zé)具體的功能實(shí)現(xiàn)->具體實(shí)現(xiàn)細(xì)節(jié))(非必須,也可以是個(gè)方法)
  • 角色二:命令接口(協(xié)議)(Command:命令抽象)
  • 角色三:具體的命令(ConcreteCmmand:具體的命令,作用:負(fù)責(zé)調(diào)用接收者邏輯方法,行為方法)
  • 角色四:請(qǐng)求者角色(Invoker:調(diào)用執(zhí)行命令)
  • 角色五:客戶端

結(jié)構(gòu)圖

引用一下大話設(shè)計(jì)模式中的結(jié)構(gòu)圖

提出需求

實(shí)現(xiàn)undo和redo的功能

分析需求

undo好redo的功能的本質(zhì)是命令隊(duì)列中的命令的規(guī)律執(zhí)行。閑言碎語(yǔ)不要講,咱們直接開擼。

代碼結(jié)構(gòu)

SQLExcute扮演的是Receiver,CommandManager扮演Invoke,其他的兩個(gè)角色就一目了然了。我們看下每個(gè)類具體的代碼。

  • ICommand
/**
 * @Author: ming.wang
 * @Date: 2019/3/7 16:42
 * @Description:
 */
public interface ICommand {

    void uodo();

    void excute();

}
  • InsertIntoCommand
/**
 * @Author: ming.wang
 * @Date: 2019/3/11 17:23
 * @Description:
 */
@Getter
@Setter
@ToString
public class InsertIntoCommand implements ICommand {

    private SQLExcute sqlExcute;

    private String id;

    public InsertIntoCommand(SQLExcute sqlExcute, String id) {
        this.sqlExcute = sqlExcute;
        this.id = id;
    }

    @Override
    public void uodo() {
        sqlExcute.delete(id);
    }

    @Override
    public void excute() {
        sqlExcute.insertInto(id);
    }
}
  • SQLExcute
/**
 * @Author: ming.wang
 * @Date: 2019/3/12 9:52
 * @Description:
 */
@Getter
@Setter
@ToString
public class SQLExcute {

    public void insertInto(String id) {
        System.out.println("插入一條數(shù)據(jù),id:" + id);
    }

    public void delete(String id) {
        System.out.println("刪除一條數(shù)據(jù),id:" + id);
    }
}
  • CommandManager
/**
 * @Author: ming.wang
 * @Date: 2019/3/11 17:26
 * @Description:
 */
public class CommandManager {

    private Stack<ICommand> redoStacks = new Stack<>();
    private Stack<ICommand> undoStacks = new Stack<>();

    public void excute(ICommand iCommand) {
        iCommand.excute();
        undoStacks.push(iCommand);
        if (!redoStacks.isEmpty()) {
            redoStacks.clear();
        }
    }

    public void uodo() {
        if (!undoStacks.isEmpty()) {
            ICommand pop = undoStacks.pop();
            pop.uodo();
            redoStacks.push(pop);
        }
    }

    public void redo() {
        if (!redoStacks.isEmpty()) {
            ICommand pop = redoStacks.pop();
            pop.excute();
        }
    }

}
  • Test
/**
 * @Author: ming.wang
 * @Date: 2019/3/11 16:44
 * @Description:
 */
public class Test {
    public static void main(String[] args) throws InterruptedException {
        CommandManager commandManager = new CommandManager();
        SQLExcute sqlExcute = new SQLExcute();
        InsertIntoCommand intoCommand1 = new InsertIntoCommand(sqlExcute, "1");
        InsertIntoCommand intoCommand2 = new InsertIntoCommand(sqlExcute, "2");
        System.out.println("執(zhí)行命令");
        commandManager.excute(intoCommand1);
        commandManager.excute(intoCommand2);

        System.out.println("執(zhí)行undo");
        commandManager.uodo();
        commandManager.uodo();

        System.out.println("執(zhí)行redo");
        commandManager.redo();
        commandManager.redo();

    }
}

運(yùn)行結(jié)果

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

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

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