設計模式之狀態模式

介紹

  1. 其行爲由狀態決定,不一樣狀態下有不一樣的行爲。
  2. 狀態模式下的行爲是平行的、不可替換的(策略模式的行爲是彼此獨立、能夠替換的)
  3. 狀態模式下,不一樣的狀態對象(注意是狀態對象)擁有一個抽象的狀態基類

定義

當一個狀態的內在狀態發生變化容許改變其行爲,這個對象看起來像是改變了其類(多態)設計模式

使用場景

  1. 一個對象的行爲取決於它的狀態,而且它必須在運行時根據狀態改變他的行爲
  2. 代碼中包含大量和狀態相關的條件語句,且這些分之語句依賴於該對象的狀態
  3. 狀態模式將每一個條件分之放入一個獨立的類中,使得咱們能夠根據對象自身的狀態狀況做爲一個對象,這個對象不依賴其餘對象而獨立存在,經過多態去除重複的,過多的if-else等分之語句

UML類圖

說明

  1. Context:環境類,實現客戶端感興趣的方法,維護一個State實例對象,State對象定義了當前的狀態,經過State對象的多態特性,自動調用其狀態下該有的方法
  2. State:抽象狀態基類或者狀態接口,定義一些方法或者接口,即是狀態下應有的行爲
  3. ConcreteStateA、ConcreteStateB:具體狀態類,每一個具體狀態下實現抽象類Stat中定義的方法或者接口,實現不一樣狀態下的不一樣行爲

具體實現

咱們都知道電視在開機狀態下能夠實現調節頻道,調節音量等操做;在關機狀態下只能開機操做,而頻道和音量調節都不能實現。下面咱們就對這種應用場景實現其具體代碼:ide

  • TvState /** * 電視操做基類 */ public interface TvState { //下一個頻道 void nextChannel(); //上一個頻道 void prevChannel(); //增長音量 void turnUp(); //減少音量 void turnDown(); } TvStat類中定義了操做電視的共有方法,不一樣狀態下應有其具體實現類源碼分析

  • PowerOffState /** * 關機狀態下的邏輯 */ public class PowerOffState implements TvState { @Override public void nextChannel() { System.out.println("PowerOffState->nextChannel"); }spa

    @Override
          public void prevChannel() {
              System.out.println("PowerOffState->prevChannel");
          }
      
          @Override
          public void turnUp() {
              System.out.println("PowerOffState->turnUp");
          }
      
          @Override
          public void turnDown() {
              System.out.println("PowerOffState->turnDown");
          }
      }
    複製代碼

關機狀態下的具體實現,此狀態下電視的頻道和音調節量都不能操做設計

  • PowerOnState /** * 開機狀態下的操做邏輯實現類 */ public class PowerOnState implements TvState {code

    @Override
          public void nextChannel() {
              System.out.println("PowerOnState->nextChannal");
          }
      
          @Override
          public void prevChannel() {
              System.out.println("PowerOnState->prevChannel");
          }
      
          @Override
          public void turnUp() {
              System.out.println("PowerOnState->turnUp");
          }
      
          @Override
          public void turnDown() {
              System.out.println("PowerOnState->turnUp");
          }
      }
    複製代碼

開機狀態下的具體實現,可以正常的對電視進行頻道和音量的調節操做cdn

  • PowerController /** * 電源控制接口 */ public interface PowerController {對象

    //開機
          void powerOn();
          //關機
          void powerOff();
      }
    複製代碼

電源控制類,TvState的具體實現類中的具體行爲就是因電源狀態發生改變而改變的。blog

  • TVController /** * 電視控制類,實現電源接口 * 內部保留TvState對象,實現電視具體的邏輯操做 */ public class TvController implements PowerController { //保留TvState實例對象,調用其對應狀態下的對象方法 private TvState mTvState;接口

    private void setTvState(TvState state){
              mTvState = state;
          }
      
          @Override
          public void powerOn() {
              setTvState(new PowerOnState());
              System.out.println("TV->powerOn");
          }
      
          @Override
          public void powerOff() {
              setTvState(new PowerOffState());
              System.out.println("TV->powerOff");
          }
      
          /**
           *如下各類操做電視的邏輯分別是在對應電視開關機狀態下邏輯實現
           */
      
          public void nextChannel(){
              mTvState.nextChannel();
          }
      
          public void prevChannel(){
              mTvState.prevChannel();
          }
      
          public void turnUp(){
              mTvState.turnUp();
          }
      
          public void turnDown(){
              mTvState.turnDown();
          }
      }
    複製代碼

TVController對應於Context類,實現PowerController的方法(開機和關機),經過開關機咱們得知其具體的狀態,在這種狀態下,經過具體行爲的基類TvState實例對象,應用多態特性,其對象的具體行爲自動接受其狀態牽制,達到不一樣狀態下有不一樣的具體行爲

  • 運行結果

    TV->powerOff
      PowerOffState->nextChannel
      PowerOffState->turnUp
      TV->powerOn
      PowerOnState->prevChannel
      PowerOnState->turnUp
    複製代碼

上面的實例中

  1. 咱們抽象一個TvState接口,該接口中有操做電視的全部方法,其對應有兩個實現類PowerOffState和PowerOnState
  2. 開機狀態下用戶能夠對電視進行頻道和音量的調節操做,關機狀態卻不能。這裏就側面反映了電視電源的狀態影響了其具體的行爲
  3. 狀態模式就是將這些行爲封裝在一個對象狀態類中,在進行操做時將這些功能轉發到狀態對象,致使不一樣狀態下有不一樣的行爲

總結

優勢

  1. 封裝了轉換規則,狀態類對象持有不一樣狀態下的相應行爲,達到不一樣狀態下擁有不一樣的行爲
  2. 將全部與某個狀態有關的行爲放到一個類中,而且能夠方便地增長新的狀態,只須要改變對象狀態便可改變對象的行爲。
  3. 將複雜的狀態判斷轉換成結構清晰的狀態類,保證好的擴展性和可維護性

缺點

  1. 狀態類的使用必然會增長系統類和對象的個數
  2. 應用場景的狀態模式功能劃分相對複雜,若是使用不當將致使程序結構和代碼的混亂

深度拓展

源碼分析之狀態機原型

參考文獻:Android源碼設計模式解析與實戰

相關文章
相關標籤/搜索