国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 系統(tǒng) > Android > 正文

Android編程設(shè)計模式之命令模式詳解

2019-12-12 01:24:39
字體:
供稿:網(wǎng)友

本文實例講述了Android編程設(shè)計模式之命令模式。分享給大家供大家參考,具體如下:

一、介紹

命令模式(Command Pattern),是行為型設(shè)計模式之一。命令模式相對于其他的設(shè)計模式來說并沒有那么多的條條框框,其實它不是一個很”規(guī)范“的模式,不過,就是基于這一點,命令模式相對于其他的設(shè)計模式更為靈活多變。我們接觸比較多的命令模式個例無非就是程序菜單命令,如在操作系統(tǒng)中,我們點擊”關(guān)機“命令,系統(tǒng)就會執(zhí)行一系列的操作,如先是暫停處理事件,保存系統(tǒng)的一些配置,然后結(jié)束程序進程,最后調(diào)用內(nèi)核命令關(guān)閉計算機等,對于這一系列的命令,用戶不用去管,用戶只需點擊系統(tǒng)的關(guān)機按鈕即可完成如上一系列的命令。而我們的命令模式其實也與之相同,將一系列的方法調(diào)用封裝,用戶只需調(diào)用一個方法執(zhí)行,那么所有這些被封裝的方法就會被挨個執(zhí)行調(diào)用。

二、定義

將一個請求封裝成一個對象,從而讓用戶使用不同的請求把客戶端參數(shù)化;對請求排隊或者記錄請求日志,以及支持可撤銷的操作。

三、使用場景

需要抽象出待執(zhí)行的動作,然后以參數(shù)的形式提供出來――類似于過程設(shè)計中的回調(diào)機制,而命令模式正是回調(diào)機制的一個面向?qū)ο蟮奶娲贰?/p>

在不同的時刻指定、排列和執(zhí)行請求。一個命令對象可以有與初始請求無關(guān)的生存期。

需要支持取消操作。

支持修改日志功能,這樣當系統(tǒng)崩潰時,這些修改可以被重做一遍。

需要支持事務操作。

四、命令模式的UML類圖

UML類圖:

通用模式代碼:

接收者類:

public class Receiver {  /*   * 真正執(zhí)行具體命令邏輯的方法   */  public void action(){    System.out.println("具體執(zhí)行");  }}

抽象命令接口:

public interface Command {  /*   * 執(zhí)行具體操作的命令   */  void excute();}

具體命令類:

public class ConcreteCommand implements Command {  private Receiver receiver;  public ConcreteCommand(Receiver receiver) {    this.receiver = receiver;  }  @Override  public void excute() {    //調(diào)用接收者的相關(guān)方法來執(zhí)行具體邏輯    receiver.action();  }}

請求者類:

public class Invoker {  private Command command;  public Invoker(Command command) {    this.command = command;  }  public void action(){    //調(diào)用具體命令對象的相關(guān)方法,執(zhí)行具體命令    command.excute();  }}

客戶類:

public class Client {  public static void main(String[] args) {    //構(gòu)造一個接收者對象    Receiver receiver = new Receiver();    //根據(jù)接收者對象構(gòu)造一個命令對象    Command command = new ConcreteCommand(receiver);    //根據(jù)具體的對象構(gòu)造請求者對象    Invoker invoker = new Invoker(command);    //執(zhí)行請求方法    invoker.action();  }}

角色介紹:

Receiver:接收者角色,該類負責具體實施或執(zhí)行一個請求,說得通俗點就是,執(zhí)行具體邏輯的角色,以本節(jié)開頭的”關(guān)機“命令操作為例,其接收者角色就是真正執(zhí)行各項關(guān)機邏輯的底層代碼。任何一個類都可以成為一個接收者,而在接收者類中封裝具體操作邏輯的方法我們則稱為行動方法。

Command:命令角色,定義所有具體命令類的抽象接口。

ConcreteCommand:具體命令角色,該類實現(xiàn)了Command接口,在execute方法中調(diào)用接收者角色的相關(guān)方法,在接收者和命令執(zhí)行的具體行為之間加以弱耦合。而execute則通常稱為執(zhí)行方法,如本文開頭所述”關(guān)機“的操作實現(xiàn),具體可能還包含很多相關(guān)的操作,比如保存數(shù)據(jù)、關(guān)閉文件、結(jié)束進程等,如果將這一系列具體的邏輯處理看作接收者,那么調(diào)用這些具體邏輯的方法就可以看作是執(zhí)行方法。

Invoker:請求者角色,該類的職責就是調(diào)用命令對象執(zhí)行具體的請求,相關(guān)的方法我們稱為行動方法,還是用”關(guān)機“為例,”關(guān)機“這個菜單命令一般就對應一個關(guān)機方法,我們點擊了”關(guān)機“命令后,由這個關(guān)機方法去調(diào)用具體的命令執(zhí)行具體的邏輯,這里的”關(guān)機“對應的這個方法就可以看作是請求者。

Client:客戶端類,Client可以創(chuàng)建具體的命令對象,并且設(shè)置命令對象的接收者。Tips:不能把Clinet理解為我們平常說的客戶端,這里的Client是一個組裝命令對象和接受者對象的角色,或者你把它理解為一個裝配者。

五、簡單實現(xiàn)

以推箱子游戲為例,一般游戲中會有五個按鈕,分別是左移、右移、下移、上移和撤銷。那么玩游戲的人就是客戶端,五個按鈕就是調(diào)用者,執(zhí)行具體按鈕命令的方法是命令角色。

接收者角色:

public class PushBox {  /**   * 執(zhí)行向左命令   */  public void toLeft(){    System.out.println("向左");  }  /**   * 執(zhí)行向右命令   */  public void toRight(){    System.out.println("向右");  }  /**   * 執(zhí)行向下命令   */  public void toDown(){    System.out.println("向下");  }  /**   * 執(zhí)行向上命令   */  public void toUp(){    System.out.println("向上");  }  /**   * 執(zhí)行撤銷命令   */  public void revoke(){    System.out.println("撤銷");  }}

抽象命令接口:

public interface Command {  /**   * 命令執(zhí)行方法   */  void execute();  /**   * 獲取命令類型   */  void getCommand();}

具體命令者,左移命令類:

public class LeftCommand implements Command{  //持有一個接受推箱子游戲?qū)ο蟮囊? private PushBox pushBox;  public LeftCommand(PushBox pushBox){    this.pushBox = pushBox;  }  @Override  public void execute() {    //調(diào)用具體命令    pushBox.toLeft();  }  @Override  public void getCommand() {    System.out.print("向左-->");  }}

具體命令者,右移命令類:

public class RightCommand implements Command{  //持有一個接受推箱子游戲?qū)ο蟮囊? private PushBox pushBox;  public RightCommand(PushBox pushBox){    this.pushBox = pushBox;  }  @Override  public void execute() {    //調(diào)用具體命令    pushBox.toRight();  }  @Override  public void getCommand() {    System.out.print("向右-->");  }}

具體命令者,上移命令類:

public class UpCommand implements Command{  //持有一個接受推箱子游戲?qū)ο蟮囊? private PushBox pushBox;  public UpCommand(PushBox pushBox){    this.pushBox = pushBox;  }  @Override  public void execute() {    //調(diào)用具體命令    pushBox.toUp();  }  @Override  public void getCommand() {    System.out.print("向上-->");  }}

具體命令者,下移命令類:

public class DownCommand implements Command{  //持有一個接受推箱子游戲?qū)ο蟮囊? private PushBox pushBox;  public DownCommand(PushBox pushBox){    this.pushBox = pushBox;  }  @Override  public void execute() {    //調(diào)用具體命令    pushBox.toDown();  }  @Override  public void getCommand() {    System.out.print("向下-->");  }}

具體命令者,撤銷命令類:

public class RevokeCommand implements Command{  //持有一個接受推箱子游戲?qū)ο蟮囊? private PushBox pushBox;  public RevokeCommand(PushBox pushBox){    this.pushBox = pushBox;  }  @Override  public void execute() {    //調(diào)用具體命令    pushBox.revoke();;  }  @Override  public void getCommand() {  }}

請求者類,命令由按鈕發(fā)起:

public class Buttons {  private LeftCommand leftCommand; //向左移動的命令對象引用  private RightCommand rightCommand; //向右移動的命令對象引用  private UpCommand upCommand; //向上移動的命令對象引用  private DownCommand downCommand; //向下移動的命令對象引用  private RevokeCommand revokeCommand; //撤銷命令對象引用  private ArrayList<Command> commandList = new ArrayList<Command>();//用于記錄命令動作  /**   * 獲取執(zhí)行命令   */  public void getCommandList(){    for(Command c : commandList){      c.getCommand();    }    System.out.println("");  }  /**   * 設(shè)置向左移動的命令對象   *   * @param leftCommand 向左移動的命令對象   */  public void setLeftCommand(LeftCommand leftCommand){    this.leftCommand = leftCommand;  }  /**   * 設(shè)置向右移動的命令對象   *   * @param rightCommand 向右移動的命令對象   */  public void setRightCommand(RightCommand rightCommand){    this.rightCommand = rightCommand;  }  /**   * 設(shè)置向上移動的命令對象   *   * @param upCommand 向上移動的命令對象   */  public void setUpCommand(UpCommand upCommand){    this.upCommand = upCommand;  }  /**   * 設(shè)置向下移動的命令對象   *   * @param downCommand 向下移動的命令對象   */  public void setDownCommand(DownCommand downCommand){    this.downCommand = downCommand;  }  /**   * 設(shè)置撤銷命令對象   *   * @param revokeCommand 撤銷命令對象   */  public void setRevokeCommand(RevokeCommand revokeCommand){    this.revokeCommand = revokeCommand;  }  /**   * 按下向左按鈕   */  public void toLeft(){    leftCommand.execute();    commandList.add(leftCommand);  }  /**   * 按下向右按鈕   */  public void toRight(){    rightCommand.execute();    commandList.add(rightCommand);  }  /**   * 按下向上按鈕   */  public void toUp(){    upCommand.execute();    commandList.add(upCommand);  }  /**   * 按下向下按鈕   */  public void toDown(){    downCommand.execute();    commandList.add(downCommand);  }  /**   * 按下撤銷按鈕   */  public void toRevoke(){    revokeCommand.execute();    commandList.remove(commandList.size()-1);  }}

客戶端調(diào)用:

public class Client {  public static void main(String[] args) {    //首先創(chuàng)建游戲    PushBox pushBox = new PushBox();    //根據(jù)游戲構(gòu)造5種命令    LeftCommand leftCommand = new LeftCommand(pushBox);    RightCommand rightCommand = new RightCommand(pushBox);    UpCommand upCommand = new UpCommand(pushBox);    DownCommand downCommand = new DownCommand(pushBox);    RevokeCommand revokeCommand = new RevokeCommand(pushBox);    //按鈕可以執(zhí)行不同命令    Buttons buttons = new Buttons();    buttons.setLeftCommand(leftCommand);    buttons.setRightCommand(rightCommand);    buttons.setUpCommand(upCommand);    buttons.setDownCommand(downCommand);    buttons.setRevokeCommand(revokeCommand);    //執(zhí)行操作    buttons.toLeft();    buttons.toDown();    buttons.toDown();    buttons.toRight();    buttons.getCommandList();    buttons.toRevoke();    buttons.toUp();    buttons.toLeft();    buttons.toDown();    buttons.toUp();    buttons.getCommandList();  }}

執(zhí)行結(jié)果:

向左向下向下向右向左-->向下-->向下-->向右-->撤銷向上向左向下向上向左-->向下-->向下-->向上-->向左-->向下-->向上-->

在這么長的代碼之后是不是覺得很煩瑣,明明可以很簡單的實現(xiàn),如下:

public class Client {  public static void main(String[] args) {    //首先創(chuàng)建游戲    PushBox pushBox = new PushBox();    pushBox.toDown();    pushBox.toRight();    pushBox.toUp();  }}

其實設(shè)計模式有一個重要的原則:對修改關(guān)閉對擴展開放。如果使用如上的簡單方式,那么以后的修改只能去修改PushBox類,然后修改Client類,這顯然違反了這一原則。如果使用命令模式,那么Client類無需修改,只需要修改PushBox類的內(nèi)部操作,Client類無需知道具體的內(nèi)部實現(xiàn)。

六、Android源碼中的命令模式

1、PackageHandler

PackageManagerService中,其對包的相關(guān)消息處理右其內(nèi)部類PackageHandler承擔,其將需要處理的請求作為對象通過消息傳遞給相關(guān)的方法,而對于包的安裝、移動以及包大小的測量則分別封裝為HandlerParams的具體子類InstallParams、MoveParams和MeasureParams。

源碼如下:

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;    final boolean startCopy() {      boolean res;      try {        if (DEBUG_INSTALL) Slog.i(TAG, "startCopy");        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();}

可以看出HandlerParams也是一個抽象命令者。

七、總結(jié)

優(yōu)點:

命令模式的封裝性很好,更弱的耦合性,更靈活的控制性以及更好的擴展性。

缺點:

類的膨脹,大量衍生類的創(chuàng)建。

更多關(guān)于Android相關(guān)內(nèi)容感興趣的讀者可查看本站專題:《Android開發(fā)入門與進階教程》、《Android調(diào)試技巧與常見問題解決方法匯總》、《Android基本組件用法總結(jié)》、《Android視圖View技巧總結(jié)》、《Android布局layout技巧總結(jié)》及《Android控件用法總結(jié)

希望本文所述對大家Android程序設(shè)計有所幫助。

發(fā)表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發(fā)表
主站蜘蛛池模板: 德化县| 台湾省| 海伦市| 贺兰县| 东莞市| 永川市| 岐山县| 怀来县| 理塘县| 那坡县| 博爱县| 化州市| 会泽县| 潼南县| 嵊泗县| 绍兴县| 屯门区| 丘北县| 黔西县| 漯河市| 宜川县| 大新县| 长春市| 平江县| 景宁| 凤城市| 政和县| 汨罗市| 进贤县| 湘阴县| 水城县| 民勤县| 绿春县| 石家庄市| 当阳市| 西平县| 扎鲁特旗| 新邵县| 平和县| 哈尔滨市| 株洲市|