源碼地址:https://github.com/weilanhanf/PythonDesignPatterns
說明:
在軟件開發過程中,各種應用程序可能會根據不同的情況做出不同的處理。最直接的方案就是把所有的可能發生的情況都考慮到。然后使用條件語句對不同情況的作出判斷並進行處理。但是假如狀態比較復雜,就會出現多個判斷語句,判斷語句中又包含這各種操作,這顯然是不受歡迎的。狀態模式的出現就是為了解決這種問題。
狀態模式用於解決系統中復雜對象的狀態轉換以及不同狀態下行為的封裝問題,將一個對象的狀態從該對象中分離出來,封裝到專門的狀態類中,使得對象狀態可以靈活變化。
狀態模式:允許一個對象在其內部狀態改變時改變它的行為,即不同的狀態對應了不同的行為。對象看起來似乎修改了它的類。很多情況下,一個對象的行為取決於一個或者多個動態變化的屬性。這樣的屬性叫做狀態,這樣的對象叫做有狀態的對象。其狀態是從事先定義好的一系列值中取出的。當一個這樣的對象與外部事件產生互動時,其內部狀態就會改變,從而使得系統的行為也隨之改變。
對於客戶端而言,無須關心對象狀態的轉換以及對象所處的當前狀態,無論對於何種狀態的對象,客戶端都可以一致處理
狀態模式的結構
狀態模式包含以下3個角色: Context(環境類) State(抽象狀態類) ConcreteState(具體狀態類)
實例:
電梯在我們周邊隨處可見,電梯的控制邏輯中心是由電梯控制器實現的。電梯的控制邏輯,即使簡單點設計,把狀態分成開門狀態,停止狀態和運行狀態,操作分成開門、關門、運行、停止,那流程也是很復雜的。首先,開門狀態不能開門、運行、停止;停止狀態不能關門,停止;運行狀態不能開門、關門、運行。要用一個一個if…else…實現,首先代碼混亂,不易維護;二是不易擴展。
但是可以看出的是,每個操作僅僅是一個操作,狀態切換與操作是分離的,這也造成后來操作和狀態“相互配合”的“手忙腳亂”。如果把狀態抽象成一個類,每個狀態為一個子類,每個狀態實現什么操作,不實現什么操作,僅僅在這個類中具體實現就可以了。
#實現抽象的狀態類 class LiftState: def open(self): pass def close(self): pass def run(self): pass def stop(self): pass #實現各個具體的狀態類 class OpenState(LiftState): def open(self): print("OPEN:The door is opened...") return self def close(self): print("OPEN:The door start to close...") print("OPEN:The door is closed") return StopState() def run(self): print("OPEN:Run Forbidden.") return self def stop(self): print("OPEN:Stop Forbidden.") return self class RunState(LiftState): def open(self): print("RUN:Open Forbidden.") return self def close(self): print("RUN:Close Forbidden.") return self def run(self): print("RUN:The lift is running...") return self def stop(self): print("RUN:The lift start to stop...") print("RUN:The lift stopped...") return StopState() class StopState(LiftState): def open(self): print("STOP:The door is opening...") print("STOP:The door is opened...") return OpenState() def close(self): print("STOP:Close Forbidden") return self def run(self): print("STOP:The lift start to run...") return RunState() def stop(self): print("STOP:The lift is stopped.") return self #為在業務中調度狀態轉移,還需要將上下文進行記錄,需要一個上下文的類 class Context: lift_state="" def getState(self): return self.lift_state def setState(self,lift_state): self.lift_state=lift_state def open(self): self.setState(self.lift_state.open()) def close(self): self.setState(self.lift_state.close()) def run(self): self.setState(self.lift_state.run()) def stop(self): self.setState(self.lift_state.stop()) #這樣,在進行電梯的調度時,只需要調度Context就可以了。業務邏輯中如下 if __name__=="__main__": ctx = Context() ctx.setState(StopState()) ctx.open() ctx.run() ctx.close() ctx.run() ctx.stop()
打印結果:
STOP:The door is opening...
STOP:The door is opened...
OPEN:Run Forbidden.
OPEN:The door start to close...
OPEN:The door is closed
STOP:The lift start to run...
RUN:The lift start to stop...
RUN:The lift stopped...
模式優點
封裝了狀態的轉換規則,可以對狀態轉換代碼進行集中管理,而不是分散在一個個業務方法中 。將所有與某個狀態有關的行為放到一個類中,只需要注入一個不同的狀態對象即可使環境對象擁有不同的行為。 允許狀態轉換邏輯與狀態對象合成一體,而不是提供一個巨大的條件語句塊,可以避免使用龐大的條件語句來將業務方法和狀態轉換代碼交織在一起。 可以讓多個環境對象共享一個狀態對象,從而減少系統中對象的個數。
模式缺點
會增加系統中類和對象的個數,導致系統運行開銷增大。 結構與實現都較為復雜,如果使用不當將導致程序結構和代碼混亂,增加系統設計的難度 。對開閉原則的支持並不太好,增加新的狀態類需要修改負責狀態轉換的源代碼,否則無法轉換到新增狀態;而且修改某個狀態類的行為也需要修改對應類的源代碼。
模式適用環境
對象的行為依賴於它的狀態(例如某些屬性值),狀態的改變將導致行為的變化 。在代碼中包含大量與對象狀態有關的條件語句,這些條件語句的出現會導致代碼的可維護性和靈活性變差,不能方便地增加和刪除狀態,並且導致客戶類與類庫之間的耦合增強