溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Android中命令模式的作用是什么

發(fā)布時間:2021-06-28 17:57:46 來源:億速云 閱讀:108 作者:Leah 欄目:移動開發(fā)

今天就跟大家聊聊有關Android中命令模式的作用是什么,可能很多人都不太了解,為了讓大家更加了解,小編給大家總結了以下內容,希望大家根據這篇文章可以有所收獲。

一、介紹

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

二、定義

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

三、使用場景

需要抽象出待執(zhí)行的動作,然后以參數的形式提供出來——類似于過程設計中的回調機制,而命令模式正是回調機制的一個面向對象的替代品。

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

需要支持取消操作。

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

需要支持事務操作。

四、命令模式的UML類圖

UML類圖:

Android中命令模式的作用是什么

通用模式代碼:

接收者類:

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() {
    //調用接收者的相關方法來執(zhí)行具體邏輯
    receiver.action();
  }
}

請求者類:

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

客戶類:

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

角色介紹:

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

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

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

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

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

五、簡單實現

以推箱子游戲為例,一般游戲中會有五個按鈕,分別是左移、右移、下移、上移和撤銷。那么玩游戲的人就是客戶端,五個按鈕就是調用者,執(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{
  //持有一個接受推箱子游戲對象的引用
  private PushBox pushBox;
  public LeftCommand(PushBox pushBox){
    this.pushBox = pushBox;
  }
  @Override
  public void execute() {
    //調用具體命令
    pushBox.toLeft();
  }
  @Override
  public void getCommand() {
    System.out.print("向左-->");
  }
}

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

public class RightCommand implements Command{
  //持有一個接受推箱子游戲對象的引用
  private PushBox pushBox;
  public RightCommand(PushBox pushBox){
    this.pushBox = pushBox;
  }
  @Override
  public void execute() {
    //調用具體命令
    pushBox.toRight();
  }
  @Override
  public void getCommand() {
    System.out.print("向右-->");
  }
}

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

public class UpCommand implements Command{
  //持有一個接受推箱子游戲對象的引用
  private PushBox pushBox;
  public UpCommand(PushBox pushBox){
    this.pushBox = pushBox;
  }
  @Override
  public void execute() {
    //調用具體命令
    pushBox.toUp();
  }
  @Override
  public void getCommand() {
    System.out.print("向上-->");
  }
}

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

public class DownCommand implements Command{
  //持有一個接受推箱子游戲對象的引用
  private PushBox pushBox;
  public DownCommand(PushBox pushBox){
    this.pushBox = pushBox;
  }
  @Override
  public void execute() {
    //調用具體命令
    pushBox.toDown();
  }
  @Override
  public void getCommand() {
    System.out.print("向下-->");
  }
}

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

public class RevokeCommand implements Command{
  //持有一個接受推箱子游戲對象的引用
  private PushBox pushBox;
  public RevokeCommand(PushBox pushBox){
    this.pushBox = pushBox;
  }
  @Override
  public void execute() {
    //調用具體命令
    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("");
  }
  /**
   * 設置向左移動的命令對象
   *
   * @param leftCommand 向左移動的命令對象
   */
  public void setLeftCommand(LeftCommand leftCommand){
    this.leftCommand = leftCommand;
  }
  /**
   * 設置向右移動的命令對象
   *
   * @param rightCommand 向右移動的命令對象
   */
  public void setRightCommand(RightCommand rightCommand){
    this.rightCommand = rightCommand;
  }
  /**
   * 設置向上移動的命令對象
   *
   * @param upCommand 向上移動的命令對象
   */
  public void setUpCommand(UpCommand upCommand){
    this.upCommand = upCommand;
  }
  /**
   * 設置向下移動的命令對象
   *
   * @param downCommand 向下移動的命令對象
   */
  public void setDownCommand(DownCommand downCommand){
    this.downCommand = downCommand;
  }
  /**
   * 設置撤銷命令對象
   *
   * @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);
  }
}

客戶端調用:

public class Client {
  public static void main(String[] args) {
    //首先創(chuàng)建游戲
    PushBox pushBox = new PushBox();
    //根據游戲構造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í)行結果:

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

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

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

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

六、Android源碼中的命令模式

1、PackageHandler

PackageManagerService中,其對包的相關消息處理右其內部類PackageHandler承擔,其將需要處理的請求作為對象通過消息傳遞給相關的方法,而對于包的安裝、移動以及包大小的測量則分別封裝為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也是一個抽象命令者。

七、總結

優(yōu)點:

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

缺點:

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

看完上述內容,你們對Android中命令模式的作用是什么有進一步的了解嗎?如果還想了解更多知識或者相關內容,請關注億速云行業(yè)資訊頻道,感謝大家的支持。

向AI問一下細節(jié)

免責聲明:本站發(fā)布的內容(圖片、視頻和文字)以原創(chuàng)、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI