1. 程式人生 > >狀態模式——State 更好的實現狀態機

狀態模式——State 更好的實現狀態機

               

1. 概述

    The intent of the STATE pattern is to distribute state-specific logic across classes that represent an object’s state.

    STATE 設計模式的目的 是:將特定狀態相關的邏輯分散到一些類的狀態類中。

 

2. 例項

    旋轉門: Consider the model of the state of a carousel door(revolving door). A carousel is a large, smart rack that accepts material through a doorway and stores the material according to a bar code ID on it. The door operates with a single button. See the state diagram below for some detail.

 

    旋轉門的狀態圖:(狀態圖細節見 4. )


 

3. 狀態模型的兩種實現方法

    3.1 方法一: switch

  

Observable是java.util中的類^^居然以前都不曉得哦,該打!

 

Door的具體實現如下:

Java程式碼   收藏程式碼
  1. import
     java.util.Observable;  
  2.   
  3. /** 
  4.  * This class provides an initial model of a carousel door 
  5.  * that manages its state without moving state-specific 
  6.  * logic out to state classes. 
  7.  */  
  8. public class Door extends Observable {  
  9.     public final int CLOSED = -1;  
  10.     public final int OPENING = -2;  
  11.     public final int OPEN = -3;  
  12.     public final int CLOSING = -4;  
  13.     public final int STAYOPEN = -5;  
  14.   
  15.     private int state = CLOSED;  
  16.   
  17.     /** 
  18.      * The carousel user has touched the carousel button. This "one touch" 
  19.      * button elicits different behaviors, depending on the state of the door. 
  20.      */  
  21.     public void touch() {  
  22.         switch (state)  
  23.         {  
  24.             case OPENING:  
  25.             case STAYOPEN:  
  26.                 setState(CLOSING);  
  27.                 break;  
  28.             case CLOSING:  
  29.             case CLOSED:  
  30.                 setState(OPENING);  
  31.                 break;  
  32.             case OPEN:  
  33.                 setState(STAYOPEN);  
  34.                 break;  
  35.             default:  
  36.                 throw new Error("can't happen");  
  37.         }  
  38.     }  
  39.   
  40.     /**  
  41.      * This is a notification from the mechanical carousel that  
  42.      * the door finished opening or shutting. 
  43.      */  
  44.     public void complete() {  
  45.         if (state == OPENING)  
  46.             setState(OPEN);  
  47.         else if (state == CLOSING)  
  48.             setState(CLOSED);  
  49.     }  
  50.   
  51.     /** 
  52.      * This is a notification from the mechanical carousel that the 
  53.      * door got tired of being open. 
  54.      */  
  55.         public void timeout() {  
  56.             setState(CLOSING);  
  57.         }  
  58.        
  59.     /** 
  60.      * @return a textual description of the door's state 
  61.      */  
  62.     public String status()  
  63.     {  
  64.         switch (state)  
  65.         {  
  66.             case OPENING:  
  67.                 return "Opening";  
  68.             case OPEN:  
  69.                 return "Open";  
  70.             case CLOSING:  
  71.                 return "Closing";  
  72.             case STAYOPEN:  
  73.                 return "StayOpen";  
  74.             default:  
  75.                 return "Closed";  
  76.         }  
  77.     }  
  78.   
  79.     private void setState(int state)  
  80.     {  
  81.         this.state = state;  
  82.         setChanged();  
  83.         notifyObservers();  
  84.     }  
  85. }  
 

但是採用這種實現,有一個缺陷:state變數在Door類的實現中渾身擴散,就像癌症一般!

 

 

    3.2 方法二: State Pattern

 

    A. 基本的 State Pattern 實現


 

    以上設計方式要求每個狀態子類例項內部“ hold 住”一個 Door2 例項的引用,這樣才能完成 Door2 例項和它的各個狀態例項時間的互相通訊。這種設計要求一個狀態例項對應一個 Door2 例項,這樣一來,一個狀態例項就只能為一個 Door2 例項服務╮ ( ╯▽╰ ) ╭

    客戶端這樣呼叫:

Java程式碼   收藏程式碼
  1. public static void main(String[] args){  
  2.         Door2 door=new Door2();  
  3.           
  4.         //1. 初始狀態  
  5.         System.out.println(door.status());  
  6.           
  7.         //2. 轉移到Opening狀態  
  8.         door.touch();  
  9.         System.out.println(door.status());  
  10.           
  11.         //3. 轉移到Open狀態  
  12.         door.complete();  
  13.         System.out.println(door.status());  
  14.           
  15.         //4. 轉移到Closing狀態  
  16.         door.timeout();  
  17.         System.out.println(door.status());  
  18.           
  19.         //5. 回到Closed狀態  
  20.         door.complete();  
  21.         System.out.println(door.status());  
  22.     }  

 

 

下面給出Door2類、DoorState抽象類、DoorStayOpen類的實現:

Door2:

Java程式碼   收藏程式碼
  1. public class Door2 extends Observable {  
  2.     public final DoorState CLOSED = new DoorClosed(this);  
  3.     public final DoorState CLOSING = new DoorClosing(this);  
  4.     public final DoorState OPEN = new DoorOpen(this);  
  5.     public final DoorState OPENING = new DoorOpening(this);  
  6.     public final DoorState STAYOPEN = new DoorStayOpen(this);  
  7.   
  8.     private DoorState state = CLOSED;  
  9.   
  10.     public void touch() {  
  11.         state.touch();  
  12.     }  
  13.   
  14.     public void complete() {  
  15.         state.complete();  
  16.     }  
  17.   
  18.     public void timeout() {  
  19.         state.timeout();  
  20.     }  
  21.   
  22.     public String status() {  
  23.         return state.status();  
  24.     }  
  25.   
  26.     protected void setState(DoorState state) {  
  27.         this.state = state;  
  28.         setChanged();  
  29.         notifyObservers();  
  30.     }  

 

DoorState抽象類:

Java程式碼   收藏程式碼
  1. public abstract class DoorState {  
  2.     protected Door2 door;  
  3.   
  4.     public abstract void touch();  
  5.   
  6.     public void complete() {  
  7.     }  
  8.   
  9.     public void timeout() {  
  10.     }  
  11.   
  12.     public String status() {  
  13.         String s = getClass().getName();  
  14.         return s.substring(s.lastIndexOf('.') + 1);  
  15.     }  
  16.   
  17.     public DoorState(Door2 door) {  
  18.         this.door = door;  
  19.     }  
  20. }  
 

DoorStayOpen類:

Java程式碼   收藏程式碼
  1. public class DoorStayOpen extends DoorState {  
  2.     public DoorStayOpen(Door2 door) {  
  3.         super(door);  
  4.     }  
  5.   
  6.     public void touch() {  
  7.         door.setState(door.CLOSING);  
  8.     }  
  9. }  
 

 

    B. State Pattern 實現 2 ——讓狀態例項( DoorState 的子類例項)為多個 Door2 例項服務

    子狀態 DoorOpen 實現轉移時只負責返回下目標狀態是什麼,將狀態轉移的 action 留給 Door2 例項自己來做;而不是像“ A. 基本的 State Pattern 實現”那樣在 DoorOpen 內部儲存一個 Door2 例項的引用 door ,親自呼叫door.setState(door.STAYOPEN); 來實現狀態轉移

    改進後的關鍵程式碼:

   

Java程式碼   收藏程式碼
  1. public class DoorOpen extends DoorState{  
  2.        public DoorState touch(){  
  3.            return DoorState.STAYOPEN;  
  4.            // 以前是 door.setState(door.STAYOPEN);  
  5.        }  
  6.        ...  
  7. }  
  8.   
  9.    
  10.   
  11.     public class Door2 extends Observable{  
  12.        public void touch(){  
  13.            state=state.touch();  
  14.            // 以前是 state.touch();  
  15.            // 即將轉移狀態的工作留給狀態例項來做,事不關己高高掛起  
  16.        }  
  17. }   

 

 

    C. State Pattern 實現 3 ——讓狀態例項( DoorState 的子類例項)為多個 Door2 例項服務

    另一種實現這種效果的方法是:將 Door2 例項作為引數傳遞給 DoorState 的狀態轉移方法,而非建立Composite 的關聯關係(將 DoorState 的子類物件作為 Door2 的屬性)。

    也即,用“ Dependency 依賴”(弱依賴,如呼叫)代替了“ Association 關聯”(強依賴,如作為屬性進行組合)。

 

 

 

4. 狀態圖細節

    何謂 State 狀態 : Generally speaking, the state of an object depends on the collective value of the object ’ s instance variables. In some cases, most of an object ’ s attributes are fairly static once set, and one attribute is dynamic and plays a prominent role in the class ’ s logic. This attribute may represent the state of the entire object and may even be named state.



 

    4.1 State

    You can subdivide a state icon into areas that show the state  s name and activities活動 .

    3 frequently used categories of activities are entry (what happens when the system enters the state), exit (what happens when the system leaves the state), and do (what happens while the system is in the state).


 

    4.2 Transition s (Details: Event[Guard Condition]/Action)

    You can also add some details to the transition lines. You can indicate an event that causes a transition to occur (atrigger event ) and the computation (the action ) that executes and makes the state change happen.

    A guard condition : when it’s met, the transition takes place. 通常將超時作為監護條件,∵可以認為此時沒有任何event.


•源狀態 Source State :即受轉換影響的狀態

•目標狀態 Target State :當轉換完成後,物件的狀態

•觸發事件 (Trigger) Event :用來為轉換定義一個事件,包括呼叫、改變、訊號、時間四類事件

•監護條件 (Guard Condition) :布林表示式,決定是否啟用轉換、

•動作 (Action) :轉換啟用時的操作

 

幾個例項:



 

 


 

           

再分享一下我老師大神的人工智慧教程吧。零基礎!通俗易懂!風趣幽默!還帶黃段子!希望你也加入到我們人工智慧的隊伍中來!https://blog.csdn.net/jiangjunshow