編輯:關於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底層邏輯對事件的轉發處理就用到了命令模式。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的子類,用來負責包相關消息的處理,不同的請求對應不同的命令對象,然後通過命令對象來執行具體操作。
通過接觸Android源碼或者其他的一些源碼,我們知道有些地方是沒有命令接收者(Receiver)這個角色的,這是為什麼呢?
個人認為,有的命令接收實現非常簡,可以直接用少量的代碼來實現,沒有必要再增加類的數量。
一、系統運行圖 二、原理下面通過幾個問題來說明下實現的原理:1、如何實現給某個用戶發送消息呢?其實就是利用百度雲提供的REST A
本文實例講述了Android通過json向MySQL中寫入數據的方法。分享給大家供大家參考,具體如下:先說一下如何通過json將Android程序中的數據上傳到MySQL
在 Android 3.0(API level 11) 之後,Google 為 Android添加了屬性動畫(Property Animation),該動畫系統是一個強大
Android插件開發初探對於Android的插件化其實已經討論已久了,但是市面上還沒有非常靠譜成熟的插件框架供我們使用。這裡我們就嘗試性的對比一下Java中,我們使用插