Java設計模式系列之狀態模式


狀態模式(State)的定義

定義對象間的一種一對多的依賴關系,當一個對象的狀態(對象內部的屬性,可以理解成是對象的某個字段或者方法)發生改變時,有依賴於它的對象都得到通知並被自動更新。允許一個對象在其內部狀態改變時改變它的行為。對象看起來似乎修改了它的類

狀態模式(State)適用性

  1.一個對象的行為取決於它的狀態,並且它必須在運行時刻根據狀態改變它的行為。

  2.一個操作中含有龐大的多分支的條件語句,且這些分支依賴於該對象的狀態。

      這個狀態通常用一個或多個枚舉常量表示。

      通常,有多個操作包含這一相同的條件結構。

      State模式將每一個條件分支放入一個獨立的類中。

      這使得你可以根據對象自身的情況將對象的狀態作為一個對象,這一對象可以不依賴於其他對象而獨立變化。

狀態模式(State)的參與者

1.Context

      定義客戶感興趣的接口。

      維護一個ConcreteState子類的實例,這個實例定義當前狀態。

2.State

      定義一個接口以封裝與Context的一個特定狀態相關的行為。

3.ConcreteStatesubclasses

      每一子類實現一個與Context的一個狀態相關的行為。

狀態模式(State)的UML類圖

        

具體代碼實現:

定義State

//定義和Context中的狀態相對應的行為
 public interface State {
     //獲取天氣情況
     String getState();
 }

定義Context

 //定義當前的狀態
  public class Context {
  
     private State state;
  
     public State getState() {
         return state;
     }
 
     public void setState(State state) {
         this.state = state;
     }
     public String stateMessage(){
         return state.getState();
     }
 } 

定義ConcreteStatesubclasses

class Sunshine implements State{

    @Override
    public String getState() {
        
        return "晴天";
    }
    
}
class Rain implements State{

    @Override
    public String getState() {
        
        return "下雨";
    }
    
} 

測試一下

public class StateTest {
 
     public static void main(String args[]){

         Context context=new Context();
         context.setState(new Rain());

         System.out.println(context.stateMessage());

         context.setState(new Sunshine());
         System.out.println(context.stateMessage());
     }
 }

運行結果:

下雨
晴天

接下來我們用Java編程思想中的一個例子來講解一下狀態模式

  我們學習了多態,看起來似乎所有的東西都可以去繼承,因為多態是一個如此巧妙的工具。事實上,當我們使用現成的類建立新類時,如果首先考慮使用繼承技術,反倒會加重我們的設計負擔,使得事情變得復雜起來。

  更好的設計思想是首先選擇"組合",尤其是不能十分確定應該使用哪一種方式的時候。組合不會強制我們的程序設計進入繼承的層次結構中。而且,組合更加靈活,因為它可以動態選擇類型(因此也就選擇了行為),想法,繼承在編譯時就需要知道確定的類型,下面是具體代碼體現:

//相當於狀態模式中的state
class Actor {

    public void act(){
    }
}
//相當於狀態模式中的ConcreteStateSubclassess
class HappyActor extends Actor{
    public void act(){
        System.out.println("HappyActor");
    }
}
class SadActor extends Actor{
    public void act(){
        System.out.println("SadActor");
    }
}
//相當於狀態模式中的Context
class Stage{
    private Actor actor=new HappyActor();
    //改變引用actor的指向的具體類型
    public void change(){
        actor=new SadActor();
    }
    //根據狀態的不同執行不同的行為
    public void performPlay(){
        actor.act();
    }
} 

測試一下:

public class Transmogrify {

    /**
     * @param args
     */
    public static void main(String[] args) {

        Stage stage=new Stage();
        stage.performPlay();
        stage.change();
        stage.performPlay();
    }

}

運行結果:

HappyActor
SadActor

程序分析:在這里,Stage對象包含一個對Actor的引用,而Actor被初始化為HappyActor對象,這意味着performPlay()會產生某種特殊行為。既然引用在運行時可以和另一個不同的對象重新綁定起來,SadActor對象的引用可以在actor中被替換,然后由performPlay()產生的行為也隨之改變,這樣一來,我們在運行期間獲得了動態靈活性。與此相反的是,我們不能在運行期間決定繼承不同的對象,因為它要求在編譯期間完全確定下來。

大家是不是覺得狀態模式和策略模式不是一樣的嗎?我們講一下他們之間的區別和聯系:

狀態模式和策略模式的區別和聯系(取自知乎網友的回答,很精辟):

區別:
狀態模式將各個狀態所對應的操作分離開來,即對於不同的狀態,由不同的子類實現具體操作,不同狀態的切換由子類實現,當發現傳入參數不是自己這個狀態所對應的參數,則自己給Context類切換狀態;而策略模式是直接依賴注入到Context類的參數進行選擇策略,不存在切換狀態的操作聯系。
聯系:
狀態模式和策略模式都是為具有多種可能情形設計的模式,把不同的處理情形抽象為一個相同的接口,符合對擴展開放,對修改封閉的原則。還有就是,策略模式更具有一般性一些,在實踐中,可以用策略模式來封裝幾乎任何類型的規則,只要在分析過程中聽到需要在不同實踐應用不同的業務規則,就可以考慮使用策略模式處理,在這點上策略模式是包含狀態模式的功能的,策略模式是一個重要的設計模式。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM