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

首頁 > 學院 > 開發設計 > 正文

在Java中應用State設計模式

2019-11-18 12:17:30
字體:
來源:轉載
供稿:網友

  對象的狀態由各個屬性的當前值構成。當我們調用某個對象的setXXX()方法時,通常表示修改它的XXX屬性。另外,對象在執行方法時,也可能修改自己的狀態。在某些情形下,例如建立事務或機器模型時,對象的狀態可能是決定其行為的要害因素,依靠于狀態的代碼邏輯可能遍布于類的大量方法。State模式的目標就是簡化這類代碼,把依靠于狀態的邏輯集中到一組類,每一個類代表一種不同的狀態,避免if語句嵌套過深或過于復雜,轉而依靠于多態性來調用不同的方法。
  狀態模型
  假如對象的狀態信息很要害,對象會擁有一些變量來指示如何根據狀態做出相應的動作。這些變量大量地散布于復雜的多層嵌套if語句中,來描述對象如何響應可能出現的事件。用這種方式建立對象模型的最大缺點在于if語句可能變得相當復雜一旦要修改對象的狀態模型,往往有多個方法的許多if語句需要調整。
  
  以傳送帶的門為例,考慮其狀態變化過程為:傳送帶的門由單個按鈕控制,并且假設初始時處于關閉狀態。按一下按鈕門開始打開,假如在門完全打開之前再次按下按鈕,門開始關閉。一旦門完全打開,它將在2秒延時之后自動開始關閉過程。要禁止門自動關閉,可以在門打開之后按一下按鈕。圖1描述了傳送門的狀態變化情況。它是一個UML狀態機(State Machine),其中click表示按下按鈕的動作。顯然,與純文字描述相比UML狀態機圖示更加直觀易懂。
  
  按照常規的設計思路(不使用State設計模式),在模擬傳送帶工作過程的軟件中,可以使用一個Door1對象代表傳送門(如圖2所示),狀態改變事件由傳送帶軟件發送給Door1對象。
   在Java中應用State設計模式(圖一)
  圖1 UML狀態機
   在Java中應用State設計模式(圖二)
  圖2 狀態改變事件發送給Door1對象
  Door1類從Observable派生,這樣客戶程序(例如一個GUI程序)就能夠方便地了解傳送門狀態。Door1類首先定義傳送門可能處于的狀態,代碼如下:
  
  public class Door1 extends Observable {
  public static final int CLOSED  = 1;
  public static final int OPENING = 2;
  public static final int OPEN   = 3;
  public static final int CLOSING = 4;
  public static final int STAYOPEN = 5;
  PRivate int state = CLOSED;
  //...
  }
  status()方法返回傳送門狀態的文字描述,如下所示:
  
  public String status() {
  switch (state) {
    case OPENING :
      return "正在打開";
    case OPEN :
      //...
    default :
      return "已關閉";
  }
  }
  當用戶點擊傳送帶的按鈕時,傳送帶程序調用Door1對象的click()方法。click()方法模擬圖1所示的狀態裝換過程:
  
  public void click() {
  if (state == CLOSED) {
    setState(OPENING);
  }
  else if (state == OPENING state == STAYOPEN) {
    setState(CLOSING);
  }
  else if (state == OPEN) {
    setState(STAYOPEN);
  }
  else if (state == CLOSING) {
    setState(OPENING);
  }
  }
  Door1類的setState()方法向觀察者通知傳送門狀態改變事件,代碼如下:
  
  private void setState(int state) {
  this.state = state;
  setChanged();
  notifyObservers();
  }
  用State模式改造
  Door1類的代碼比較復雜,整個類到處都用到了狀態變量。假如要比較圖1的狀態機和Door1類的各個狀態變換方法,將是非常困難的,click()方法尤其如此。那么,怎樣在這個例子中應用State模式呢?首先要把傳送門的各種狀態分別定義成類,如圖3所示。圖3能夠更好地與圖1的狀態機對應。更改后的類設計中,Door2包含了狀態機的上下文信息。所謂上下文信息,就是描述環境和一系列其它對象相關的信息。就本例而言,State利用一個上下文對象記錄了傳送門的當前狀態是DoorState類的哪一個實例。
  在Java中應用State設計模式(圖三)
  圖3 傳送門各個狀態
  DoorState類的構造函數要求提供一個Door2對象,DoorState的子類利用該對象傳達狀態變更信息。在這種設計方案中,DoorState的子類通過一個Door2類型的屬性綁定到特定的傳送門(Door2)對象,因而要求一個DoorState對象只被一個Door2對象引用。同時Door類要把它的狀態信息定義成局部變量,代碼如下:
  
  public class Door2 extends Observable {
  public final DoorState CLOSED  = new DoorClosed(this);
  // 按照類似方式定義DoorState類型的
  // OPENING、OPEN、CLOSING、STAYOPEN對象(略)
  private DoorState state = CLOSED;
  // ...
  }
  DoorState類是一個抽象類,由子類實現其click()方法。在狀態機中,每一個狀態均有相應的“按下按鈕”操作。修改后的設計中每一個描述狀態的類也有一個click()方法,兩者是一致的。DoorState類處理了其它可能的變換,所以DoorState的子類可以忽略無關的事件,代碼如下:
  
  public abstract class DoorState {
  protected Door2 door;
  public DoorState(Door2 door) {
    this.door = door;
  }
  public abstract void click();
  public String status() {
    String s = getClass().getName();
    return s.substring(s.lastIndexOf('.') + 1);
  }
   public void complete() { }
   public void timeout() { }
  }
  由上可以看到,現在的status()方法要比修改設計方案之前的status()方法簡單多了。新status()方法返回的結果與修改前版本的結果略有不同,它的狀態信息從類的名稱獲得。假如要返回修改設計方案之前的信息,只需把這些狀態信息分別記錄到DoorState的各個子類中,然后在這個status()方法中直接提取即可。
  
  新的設計方案中,傳送門對象(Door2)從傳送帶接收狀態改變信息的這一角色仍未改變。但現在Door2對象只需把這些狀態改變信息直接傳遞給當前的狀態對象就可以了,代碼如下:
  
  public class Door2 extends Observable {
  // ... 聲明變量
  protected void setState(DoorState state) {
    this.state = state;
    setChanged();
    notifyObservers();
  }
  public void click() {
    state.click();
  }
  // complete()、status()、timeout()都直接
  // 調用state的相應方法即可(略)
  }
  這里的click()、complete()、status()和timeout()方法體現了java類多態性的應用。所有這些方法都起著判定和選擇動作的作用,即是雖然每一個方法的代碼是不含if判定邏輯的,但實際運行時被調用的狀態對象卻不斷變化。在調用click()時會發生哪些事情呢?按照多態性規則,答案依靠于當時傳送門的狀態。修改后的代碼有效地擔負起了根據狀態執行不同動作的任務,但由于利用了多態性,它變得更加簡單了。
  
  Door2類中的setState()方法現在由DoorState的子類調用。這些DoorState的子類與圖1狀態機中的相應實體很相似,例如,狀態機中Open狀態包含Timeout和Click,DoorOpen類則包含兩個對應的方法timeout()和click()。DoorOpen類的代碼如下:
  
  public class DoorOpen extends DoorState {
  public DoorOpen(Door2 door) {
    super(door);
  }
  public void click() {
    door.setState(door.STAYOPEN);
  }
  public void timeout() {
    door.setState(door.CLOSING);
  }
  }
  從上面可以看到,利用State設計模式之后,代碼變得更簡單了。不過,細心的讀者或許已經注重到,Door2類用到的“常量”實際上是變量,這給人一種不規范的感覺。假設現在要把這些狀態常量移到_DoorConstant接口,這就需要從DoorState類消除Door2實例變量。修改辦法是:重新定義DoorState類中的click()、complete()和timeout()變換方法,把一個Door2對象以參數的形式傳遞給它們。按照這種設計方法,Door2對象調用狀態變換方法,例如click()時,將采用state.click(this)的形式。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 平武县| 牡丹江市| 闻喜县| 马鞍山市| 个旧市| 安泽县| 江北区| 濮阳县| 海林市| 安西县| 乌拉特后旗| 井研县| 紫阳县| 化州市| 鄯善县| 阿勒泰市| 娱乐| 永修县| 郯城县| 比如县| 扶绥县| 淄博市| 弋阳县| 绥宁县| 朝阳市| 福州市| 凤凰县| 西林县| 澎湖县| 宁陵县| 绥江县| 博野县| 西平县| 观塘区| 宝应县| 新干县| 长阳| 永春县| 聊城市| 葫芦岛市| 仁布县|