1. 程式人生 > >java設計模式——命令模式(Command Pattern)

java設計模式——命令模式(Command Pattern)

概述:        在軟體開發中,我們經常需要向某些物件傳送請求(呼叫其中的某個或某些方法),但是並不知道請求的接收者是誰,也不知道被請求的操作是哪個,此時,我們特別希望能夠以一種鬆耦合的方式來設計軟體,使得請求傳送者與請求接收者能夠消除彼此之間的耦合,讓物件之間的呼叫關係更加靈活,可以靈活地指定請求接收者以及被請求的操作。命令模式為此類問題提供了一個較為完美的解決方案。        命令模式可以將請求傳送者和接收者完全解耦,傳送者與接收者之間沒有直接引用關係,傳送請求的物件只需要知道如何傳送請求,而不必知道如何完成請求。 定義:        命令模式(Command Pattern):將一個請求封裝為一個物件,從而使我們可用不同的請求對客戶進行引數化;對請求排隊或者記錄請求日誌,以及支援可撤銷的操作。命令模式是一種物件行為型模式,其別名為動作(Action)模式或事務(Transaction)模式。
結構:
  • Command(抽象命令類):抽象命令類一般是一個抽象類或介面,在其中聲明瞭用於執行請求的execute()等方法,通過這些方法可以呼叫請求接收者的相關操作。
  • ConcreteCommand(具體命令類):具體命令類是抽象命令類的子類,實現了在抽象命令類中宣告的方法,它對應具體的接收者物件,將接收者物件的動作繫結其中。在實現execute()方法時,將呼叫接收者物件的相關操作(Action)。
  • Invoker(呼叫者):呼叫者即請求傳送者,它通過命令物件來執行請求。一個呼叫者並不需要在設計時確定其接收者,因此它只與抽象命令類之間存在關聯關係。在程式執行時可以將一個具體命令物件注入其中,再呼叫具體命令物件的execute()方法,從而實現間接呼叫請求接收者的相關操作。
  • Receiver(接收者):接收者執行與請求相關的操作,它具體實現對請求的業務處理。
UML圖:
場景:公司專案開發過程中,客戶有需求,直接通過專案經理來傳遞,比如客戶要改需求,無論改畫面或者改流程也好,直接跟專案經理溝通,然後專案經理根據情況找到公司相關負責人進行任務分配,關於介面的會讓UI組去完成,關於業務流程的讓開發組完成,客戶只需要最終結果就行了。 程式碼分析: /**
 * Created by **
 * 定義一個呼叫者:專案經理
*/
public class Invoker {
    private Command command;

    /**
     * 接到客戶具體命令
@param command
*/
public void setCommand(Command command){
        this.command = command;
    }

    /**
     * 執行命令
*/
public void call(){
        this.command.execute();
    }
}
/**
 * Created by **
 * 定義命令抽象類
*/
public abstract class Command {
    // 需要執行的命令
protected abstract void execute();
}
/**
 * Created by **
 * 抽象接收者:負責執行具體的任務
*/
public abstract class ReceivceGroup {
    protected abstract void add();
    protected abstract void modify();
    protected abstract void delete();
}
/**
 * Created by **
 * 具體接收者
*/
public class RequirementGroup extends ReceivceGroup {

    @Override
protected void add() {
        LogFactory.log("增加一個需求");
    }

    @Override
protected void delete() {
        LogFactory.log("刪除一個需求");
    }

    @Override
protected void modify() {
        LogFactory.log("修改需求計劃");
    }
}
/**
 * Created by **
 * 具體的命令
*/
public class AddRequirementCommand extends Command {
    private RequirementGroup requirementGroup new RequirementGroup();
    @Override
protected void execute() {
        this.requirementGroup.delete();
        this.requirementGroup.add();
        this.requirementGroup.modify();
    }
}
客戶端: // 找到專案經理
Invoker invoker = new Invoker();
// 客戶下達具體命令
AddRequirementCommand addRequirementCommand = new AddRequirementCommand();
// 經理收到這個命令
invoker.setCommand(addRequirementCommand);
// 執行命令
invoker.call();
log輸出: 08-12 17:11:59.056 22236-22236/? D/yangjun: 刪除一個需求 08-12 17:11:59.056 22236-22236/? D/yangjun: 增加一個需求 08-12 17:11:59.056 22236-22236/? D/yangjun: 修改需求計劃 優點:
  • 降低系統的耦合度。
  • 新的命令可以很容易地加入到系統中。
  • 可以比較容易地設計一個命令佇列和巨集命令(組合命令)。
  • 可以方便地實現對請求的Undo和Redo。
缺點:
  • 使用命令模式可能會導致某些系統有過多的具體命令類。因為針對每一個命令都需要設計一個具體命令類,因此某些系統可能需要大量具體命令類,這將影響命令模式的使用。
適用環境:
  • 系統需要將請求呼叫者和請求接收者解耦,使得呼叫者和接收者不直接互動。
  • 系統需要在不同的時間指定請求、將請求排隊和執行請求。 一個命令物件和請求的初始呼叫者可以有不同的生命期,換言之,最初的請求發出者可能已經不在了,而命令物件本身仍然是活動的,可以通過該命令物件去呼叫請求接收者,而無須關心請求呼叫者的存在性,可以通過請求日誌檔案等機制來具體實現。
  • 系統需要支援命令的撤銷(Undo)操作和恢復(Redo)操作。
  • 系統需要將一組操作組合在一起,即支援巨集命令
擴充套件: 巨集命令又稱為組合命令,它是命令模式和組合模式聯用的產物。
  • 巨集命令也是一個具體命令,不過它包含了對其他命令物件的引用,在呼叫巨集命令的execute()方法時,將遞迴呼叫它所包含的每個成員命令的execute()方法,
  • 一個巨集命令的成員物件可以是簡單命令,還可以繼續是巨集命令。執行一個巨集命令將執行多個具體命令,從而實現對命令的批處理。