Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android源碼中的命令模式

Android源碼中的命令模式

編輯:關於Android編程

寫在前面

從裝飾者模式到Context類族

當觀察者模式和回調機制遇上Android源碼

Android源碼中的靜態工廠方法

Android中的工廠方法模式

前面跟大家分享了裝飾者模式、觀察者模式、靜態工廠方法、工廠方法模式,今天跟大家分享下Android源碼中的命令模式。

命令模式

定義

將一個請求封裝成一個對象,從而使你可用不同的請求對客戶進行參數化,對請求排隊或記錄請求日志,以及支持可撤銷的操作。

使用場景

對於大多數請求——響應模式的功能,比較適合使用命令模式。

系統需要將請求調用者和請求接收者解耦,使得調用者和接收者不直接交互。 系統需要在不同的時間指定請求、將請求排隊(如:線程池+工作隊列)和執行請求。 系統需要支持命令的撤銷(Undo)操作和恢復(Redo)操作(比如系統掛掉之後重啟做一些恢復操作,還有數據庫的事務等)。 系統需要將一組操作組合在一起,即支持宏命令。

結構

\vcnmvLC1vbXEvcfJq6O6PC9wPg0KPHN0cm9uZz6/zbunvcfJq6OoQ2xpZW50o6k8L3N0cm9uZz6jukNsaWVudL/J0tS0tL2ovt/M5bXEw/zB7rbUz/OjrLKix9LJ6NbDw/zB7rbUz/O1xL3TytXV36GjVGlwc6O6srvE3LDRQ2xpbmV0wO294s6qztLDx8a9s6PLtbXEv827p7bLo6zV4sDvtcRDbGllbnTKx9K7uPbX6deww/zB7rbUz/O6zb3TytzV37bUz/O1xL3HyaujrLvy1d/E47DRy/zA7b3izqrSu7j217DF5NXfoaMgPHN0cm9uZz6199PD1d+9x8mro6hJbnZva2Vyo6k8L3N0cm9uZz6juri61PC199PDw/zB7rbUz/PWtNDQx+vH86Oszaizo7vhs9bT0MP8we621M/zo6i/ydLUs9bT0LbguPbD/MHuttTP86OpoaNJbnZva2VyysdDbGllbnTV5tX9tKW3osP8we6yotKqx/PD/MHu1rTQ0M/g06ay2df3tcS12Le9o6jKudPDw/zB7rbUz/O1xMjrv9qjqaGjIDxzdHJvbmc+w/zB7r3HyaujqENvbW1hbmSjqTwvc3Ryb25nPqO6tqjS5cP8we61xL3Tv9qjrMn5w/e+38zlw/zB7sDg0OjSqta00NC1xLe9t6iho9XiysfSu7j2s+nP873HyauhoyA8c3Ryb25nPr7fzOXD/MHuvcfJq6OoQ29uY3JldGVDb21tYW5ko6k8L3N0cm9uZz6jusP8we6907/atcS+38zlyrXP1rbUz/OjrM2os6O74bPW09C908rV1d+jrLKitffTw73TytXV37XEuabE3MC0zeqzycP8we7Sqta00NC1xLLZ1/ehoyA8c3Ryb25nPr3TytXV373HyaujqFJlY2VpdmVyo6k8L3N0cm9uZz6julJlY2VpdmVyysfV5tX91rTQ0MP8we61xLbUz/Oho8jOus7A4La8v8nE3LPJzqrSu7j2vdPK1dXfo6zWu9Kqy/zE3Lm7yrXP1sP8we7SqsfzyrXP1rXEz+DTprmmxNyhow0KPGgyIGlkPQ=="實現">實現

命令模式其實就是對命令進行封裝,將命令請求者和命令執行者的責任分離開來實現松耦合。 這裡我們通過一個餐廳點餐的實例來剖析一下命令模式:命令接收者Cook可以做各式各樣的菜,根據Waiter送過來的訂單來滿足顧客的需求,具體命令實現類PigCook執行做烤乳豬命令,DuckCook執行燒花鴨命令等等,Client負責組裝各個部分。

命令角色

public interface Command {
    public void execute();
    public void undo();
    public void redo();
}

命令接收者

public class Cook {

    //烤乳豬的方法
    public void cookPig(){

    }

    //燒花鴨的方法
    public void cookDuck(){

    }
}

具體命令角色

//做烤乳豬的命令
public class PigCook implements Command {

    private Cook mCook;

    public PigCook(Cook cook) {
        mCook = cook;
    }

    @Override
    public void execute() {
        mCook.cookPig();
    }

    @Override
    public void undo() {

    }

    @Override
    public void redo() {

    }
}
//做燒花鴨的命令
public class DuckCook implements Command {

    private Cook mCook;

    public DuckCook(Cook cook) {
        mCook = cook;
    }

    @Override
    public void execute() {
        mCook.cookDuck();
    }

    @Override
    public void undo() {

    }

    @Override
    public void redo() {

    }
}

調用者角色

public class Waiter {

    private Command pig;
    private Command duck;

    public void setCommandPig(Command pig) {
        this.pig = pig;
    }
    public void setCommandDuck(Command duck) {
        this.duck = duck;
    }

    /**
     * 執行正常命令,這裡省略了undo和redo操作
     */
    public void invoke(int args) {
        //可以根據具體情況選擇執行某些命令
        if(args == 0){
            pig.execute();
        }else if(args == 1){
            duck.execute();
        }
    }
}

客戶角色

public class Client {
    /**
     * 組裝操作
     */
    public void assembleAction() {

        //創建一個命令接收者
        Cook mCook = new Cook();

        //創建一個命令的具體實現對象,並指定命令接收者
        Command pig = new PigCook(mCook);
        Command duck = new DuckCook(mCook);

        Waiter mWaiter = new Waiter();//創建一個命令調用者
        //為調用者指定烤乳豬命令對象
        mWaiter.setCommandPig(pig);
        //為調用者指定燒花鴨命令對象
        mWaiter.setCommandDuck(duck);

        //發起調用烤乳豬命令請求
        mWaiter.invoke(0);
        //發起調用燒花鴨命令請求
        mWaiter.invoke(1);
    }
}

可是,為什麼要這麼復雜咧,我只是想點個菜而已嘛,直接這麼搞不就好了?

public class Client {
    /**
     * 組裝操作
     */
    public void assembleAction() {

        //創建一個命令接收者
        Cook mCook = new Cook();

        //發起調用烤乳豬命令請求
        mCook.cookPig();
        //發起調用燒花鴨命令請求
        mCook.cookDuck();
    }
}

我們知道命令模式的一個優點是支持命令的撤銷(Undo)操作和恢復(Redo)操作,如果我們像上邊一樣調用,我們要想做撤銷是不是就不那麼方便了呢。同時還可以考慮下命令模式的其他幾個優點。

總結

每一個命令都是一個操作:請求的一方發出請求,要求執行一個操作;接收的一方收到請求,並執行操作。

命令模式允許請求的一方和接收的一方獨立開來,使得請求的一方不必知道接收請求的一方的接口,更不必知道請求是怎麼被接收,以及操作是否被執行、何時被執行,以及是怎麼被執行的。

命令模式使請求本身成為一個對象,這個對象和其他對象一樣可以被存儲和傳遞。

命令模式的關鍵在於引入了抽象命令接口,且發送者針對抽象命令接口編程,只有實現了抽象命令接口的具體命令才能與接收者相關聯。

Android源碼中的命令模式

對於Android源碼來說,Android底層邏輯對事件的轉發處理就用到了命令模式。Application Framework(應用程序框架層)中PackageManagerService類(包管理部分)也用到了命令模式。PackageManagerService是Android系統的Service之一,主要功能是實現對應用包的解析、管理、卸載等操作。我們來看下具體的結構。

\

HandlerParams是命令接口,即我們的Command角色。

private abstract class HandlerParams {
    private static final int MAX_RETRIES = 4;

    /**
     * Number of times startCopy() has been attempted and had a non-fatal
     * error.
     */
    private int mRetries = 0;

    /** User handle for the user requesting the information or installation. */
    private final UserHandle mUser;
    String traceMethod;
    int traceCookie;

    HandlerParams(UserHandle user) {
        mUser = user;
    }

    UserHandle getUser() {
        return mUser;
    }

    HandlerParams setTraceMethod(String traceMethod) {
        this.traceMethod = traceMethod;
        return this;
    }

    HandlerParams setTraceCookie(int traceCookie) {
        this.traceCookie = traceCookie;
        return this;
    }

    final boolean startCopy() {
        boolean res;
        try {
            if (DEBUG_INSTALL) Slog.i(TAG, "startCopy " + mUser + ": " + this);

            if (++mRetries > MAX_RETRIES) {
                Slog.w(TAG, "Failed to invoke remote methods on default container service. Giving up");
                mHandler.sendEmptyMessage(MCS_GIVE_UP);
                handleServiceError();
                return false;
            } else {
                handleStartCopy();
                res = true;
            }
        } catch (RemoteException e) {
            if (DEBUG_INSTALL) Slog.i(TAG, "Posting install MCS_RECONNECT");
            mHandler.sendEmptyMessage(MCS_RECONNECT);
            res = false;
        }
        handleReturnCode();
        return res;
    }

    final void serviceError() {
        if (DEBUG_INSTALL) Slog.i(TAG, "serviceError");
        handleServiceError();
        handleReturnCode();
    }

    abstract void handleStartCopy() throws RemoteException;
    abstract void handleServiceError();
    abstract void handleReturnCode();
}

具體的包的安裝、移動以及包大小的測量分別在3個具體子類InstallParams、MoveParams和MeasureParams中實現。

而PackageHandler是Handler的子類,用來負責包相關消息的處理,不同的請求對應不同的命令對象,然後通過命令對象來執行具體操作。

關於Receiver

通過接觸Android源碼或者其他的一些源碼,我們知道有些地方是沒有命令接收者(Receiver)這個角色的,這是為什麼呢?

個人認為,有的命令接收實現非常簡,可以直接用少量的代碼來實現,沒有必要再增加類的數量。

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved