命令模式
定義與類型
- 定義: 命令模式將一個(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é)果
