Java命令設(shè)計(jì)模式優(yōu)雅解耦命令和執(zhí)行提高代碼可維護(hù)性
介紹
Java命令模式(Command Pattern)是一種行為型設(shè)計(jì)模式,它將請(qǐng)求封裝成一個(gè)對(duì)象,從而使不同的請(qǐng)求可以進(jìn)行參數(shù)化,并支持請(qǐng)求的排隊(duì),記錄日志,撤銷操作等.
在命令模式中,將命令請(qǐng)求者(Invoker),命令接收者(Receiver)和命令對(duì)象(Command)進(jìn)行了解耦,使得它們可以獨(dú)立地變化.具體的說,命令對(duì)象封裝了一個(gè)特定的請(qǐng)求和其對(duì)應(yīng)的操作,Invoker對(duì)象負(fù)責(zé)調(diào)用命令來執(zhí)行請(qǐng)求,而Receiver對(duì)象則負(fù)責(zé)實(shí)際執(zhí)行命令所代表的操作.
在Java中,可以通過定義一個(gè)接口來定義命令對(duì)象的基本行為,然后再定義具體的命令對(duì)象實(shí)現(xiàn)該接口.Invoker對(duì)象可以包含一個(gè)或多個(gè)命令對(duì)象,可以通過調(diào)用命令對(duì)象的execute()方法來執(zhí)行相應(yīng)的命令.而Receiver對(duì)象則負(fù)責(zé)實(shí)際執(zhí)行命令所代表的操作,其具體實(shí)現(xiàn)可以再命令對(duì)象的execute()方法中調(diào)用.
實(shí)現(xiàn)
命令對(duì)象接口
public interface Command {
/**
* 執(zhí)行
*/
void execute();
/**
* 撤銷
*/
void undo();
}
具體命令對(duì)象
public class ConcreteCommand1 implements Command {
private Receiver receiver;
private boolean isExecute;
public ConcreteCommand1(Receiver receiver) {
this.receiver = receiver;
}
/**
* 執(zhí)行
*/
@Override
public void execute() {
receiver.action1();
isExecute = true;
}
/**
* 撤銷
*/
@Override
public void undo() {
if (isExecute) {
receiver.undoAction1();
isExecute = false;
}
}
}
public class ConcreteCommand2 implements Command {
private Receiver receiver;
private boolean isExecute;
public ConcreteCommand2(Receiver receiver) {
this.receiver = receiver;
}
/**
* 執(zhí)行
*/
@Override
public void execute() {
receiver.action2();
isExecute = true;
}
/**
* 撤銷
*/
@Override
public void undo() {
if (isExecute) {
receiver.undoAction2();
isExecute = false;
}
}
}
命令接收者
public class Receiver {
public void action1() {
System.out.println("Receiver.action1() 被調(diào)用...");
}
public void action2() {
System.out.println("Receiver.action2() 被調(diào)用...");
}
public void undoAction1(){
System.out.println("Receiver.undoAction1() 被調(diào)用...");
}
public void undoAction2(){
System.out.println("Receiver.undoAction2() 被調(diào)用...");
}
}
命令請(qǐng)求者
public class Invoker {
private List<Command> commandList = new ArrayList<>();
/**
* 添加命令
*
* @param command
*/
public void addCommand(Command command) {
commandList.add(command);
}
/**
* 執(zhí)行命令
*/
public void executeCommands() {
commandList.forEach(Command::execute);
}
/**
* 撤銷命令
*/
public void undoCommands() {
for (int i = commandList.size() - 1; i >= 0; i--) {
commandList.get(i).undo();
}
}
}
測試
public class Demo {
public static void main(String[] args) {
Receiver receiver = new Receiver();
Command command1 = new ConcreteCommand1(receiver);
Command command2 = new ConcreteCommand2(receiver);
Invoker invoker = new Invoker();
invoker.addCommand(command1);
invoker.addCommand(command2);
invoker.executeCommands();
invoker.undoCommands();
}
}

再示例代碼中,定義了兩個(gè)具體的命令對(duì)象實(shí)現(xiàn),分別是ConcreteCommand1和ConcreteCommand2,它們都實(shí)現(xiàn)了Command接口,并且支持撤銷操作.每個(gè)ConcreteCommand對(duì)象內(nèi)部維護(hù)了一個(gè)boolean類型的isExecute變量,表示該命令是否已經(jīng)執(zhí)行過.如果execute()方法中,執(zhí)行具體的命令操作,并將isExecute設(shè)為true.再undo()方法中,如果該命令已經(jīng)執(zhí)行過,則執(zhí)行與execute()方法相反的操作,并將isExecute設(shè)為false.Receiver類是命令接收者,它實(shí)際執(zhí)行命令所代表的操作.Invoker類中包含了一個(gè)Command對(duì)象列表,它通過addCommand()方法向其中添加具體的Command對(duì)象,executeCommand()用于執(zhí)行所有添加的Command對(duì)象,而undoCommands()方法則用于撤銷所有添加的Command對(duì)象,執(zhí)行與撤銷的順序正好相反.
總結(jié)
優(yōu)點(diǎn)
- 解耦合,命令模式可以將命令請(qǐng)求者和命令接收者之間解耦合,使得它們之間不直接產(chǎn)生相互作用,從而提高系統(tǒng)的靈活性和可擴(kuò)展性
- 擴(kuò)展性,由于命令模式將請(qǐng)求封裝成對(duì)象,因此可以方便地新增或修改命令,而不影響其他對(duì)象的運(yùn)行.同時(shí),也可以方便地新增或修改命令接收者,從而實(shí)現(xiàn)系統(tǒng)功能的靈活變化.
- 撤銷操作,命令模式可以支持撤銷操作,使得系統(tǒng)具有回滾功能,增強(qiáng)了系統(tǒng)的容錯(cuò)性.
缺點(diǎn)
- 系統(tǒng)復(fù)雜性,使用命令模式需要增加額外的類和接口,從而增加了系統(tǒng)的復(fù)雜性
- 性能損失.由于需要將請(qǐng)求封裝成對(duì)象,因此可能會(huì)導(dǎo)致系統(tǒng)性能的降低,特別是再處理大量請(qǐng)求時(shí)
應(yīng)用場景
- 撤銷操作,如果系統(tǒng)需要支持撤銷操作,那么命令模式是一個(gè)非常好的選擇.例如:文本編輯器中的"撤銷"和"重做"操作.
- 日志記錄,命令模式可以用來記錄請(qǐng)求日志,從而實(shí)現(xiàn)系統(tǒng)的日志功能.例如:使用命令模式記錄用戶的操作記錄,實(shí)現(xiàn)系統(tǒng)的審計(jì)功能.
- 隊(duì)列請(qǐng)求.如果需要將請(qǐng)求排隊(duì),可以使用命令模式來管理請(qǐng)求隊(duì)列.例如:使用命令模式管理操作系統(tǒng)的I/O請(qǐng)求隊(duì)列.
到此這篇關(guān)于Java命令設(shè)計(jì)模式優(yōu)雅解耦命令和執(zhí)行提高代碼可維護(hù)性的文章就介紹到這了,更多相關(guān)Java命令設(shè)計(jì)模式內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java權(quán)重隨機(jī)的實(shí)現(xiàn)方法
這篇文章主要介紹了Java權(quán)重隨機(jī)的實(shí)現(xiàn)方法,實(shí)例分析了權(quán)重隨機(jī)算法的原理與完整實(shí)現(xiàn)方法,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2015-01-01
Java編程實(shí)現(xiàn)獲取當(dāng)前代碼行行號(hào)的方法示例
這篇文章主要介紹了Java編程實(shí)現(xiàn)獲取當(dāng)前代碼行行號(hào)的方法,結(jié)合實(shí)例形式分析了java基于StackTraceElement對(duì)象實(shí)現(xiàn)獲取代碼行號(hào)的相關(guān)操作技巧,需要的朋友可以參考下2017-08-08
Java利用Jackson序列化實(shí)現(xiàn)數(shù)據(jù)脫敏詳解
在項(xiàng)目中有些敏感信息不能直接展示,比如客戶手機(jī)號(hào)、身份證、車牌號(hào)等信息,展示時(shí)均需要進(jìn)行數(shù)據(jù)脫敏,防止泄露客戶隱私。本文將利用Jackson序列化實(shí)現(xiàn)數(shù)據(jù)脫敏,需要的可以參考一下2023-03-03
Java多線程Future松獲取異步任務(wù)結(jié)果輕松實(shí)現(xiàn)
這篇文章主要為大家介紹了Java多線程Future松獲取異步任務(wù)結(jié)果輕松實(shí)現(xiàn)方法,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-04-04
Java中Object.wait()和LockSupport.park()的用法
Object.wait()和LockSupport.park()都是用來使當(dāng)前線程等待的方法,本文主要介紹了Java中Object.wait()和LockSupport.park()的用法,具有一定的參考價(jià)值,感興趣的可以了解一下2024-05-05
JavaMail實(shí)現(xiàn)發(fā)送超文本(html)格式郵件的方法
這篇文章主要介紹了JavaMail實(shí)現(xiàn)發(fā)送超文本(html)格式郵件的方法,實(shí)例分析了java發(fā)送超文本文件的相關(guān)技巧,需要的朋友可以參考下2015-05-05
token工作機(jī)制及原理附Java生成token工具類
這篇文章介紹了token工作機(jī)制及原理,內(nèi)附Java生成token工具類Demo。對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-12-12

