狀態模式在某些場合中使用是非常方便的,什么叫做狀態,如果大家學過《編譯原理》就會明白 DFA M 和 NFA M,在確定有限狀態機和非確定有限狀態機中,狀態就是最小的單元,當滿足某種條件的時候,狀態就會發生改變,我們可以把時間中的一個時刻當做一個狀態,那么其實整個社會都是有狀態組成的,前一時刻到下一時刻,整個社會上的物質(空間)發生了什么樣的變化,因此狀態可以非常的大也可以非常的小,天氣變化情況是狀態,白天和黑夜也是狀態,人的生活作息等等都是狀態,因此狀態無處不在。那么狀態模式就是將一個狀態看作一個類,這與以往我們對類的理解不一樣,以往我們認為類是對對象的抽象,用來表示對象的,對象一般是具體的事物,而現在我們將狀態這種非具體的看不見的但又真實存在的事物當作類描述的東西,這一點可能需要大家理解。
那么為什么必須要狀態模式,不用狀態模式可以嗎?當然可以,但是還是回到了代碼的可維護性、可擴展性、可復用性這個層面上來考慮問題,比如我們本例的內容,考慮一個銀行系統,可以用來取款、打電話、報警、記錄這四種功能,但是考慮如下需求:在白天如果我們去取款是正常的,晚上取款就要發出警報;在白天打電話有人接,晚上打電話啟動留言功能;白天和晚上按警鈴都會報警。那么我們應該如何設計這個程序呢,當然我們可以對每一個動作(作為一個函數),在這個函數內部,我們進行判斷是白天還是黑夜,然后根據具體的情況做出反應。這樣當然是可以的,但是假如我們的狀態(白天和黑夜)非常的多呢,比如將 24 小時分成 24 個時間段(24 個狀態),那么我們對于每一個函數就要判斷 24 遍,這無疑是非常糟糕的代碼,可讀性非常的差,并且如果需求發生了改變,我們很難去修改代碼(很容易出現錯誤),但是如果我們考慮將這些狀態都作為一個類,在每一個類內部進行處理、判斷和相應的切換,這樣思路就非常的清晰,如果再增加一種狀態,代碼需要修改的地方會非常的少,對于狀態非常多的情景來說非常的方便。
最簡潔的代碼通過接口、抽象類、普通類、繼承、委托、代理模式等方式,將狀態抽象為類,然后通過控制狀態的邏輯委托不同的狀態去做不同的事情,對于每一個狀態來說又再次委托控制狀態的邏輯作出相應的動作和修改,這樣看起來比較復雜,其實仔細閱讀就會發現因為接口的原因,使得程序非常的簡潔,各個狀態分工明確,密切配合。
但是狀態模式也有一些缺點,正是因為各個狀態密切配合,在一個狀態之中要知道其他狀態的對象,這就造成了一定的關聯,狀態與狀態之間是一種緊耦合的關系,這是狀態模式的一點缺點,針對于這一點,我們可以將狀態遷移的代碼統一交給 SafeFrame 來做,這樣就要使用到了 Mediator 仲裁者模式了。
使用單例的原因是如果一直創造新的對象會對內存產生浪費,因為單例即可。同樣的使用狀態模式通過接口使用 state 變量來表示相應的狀態,不會產生混淆和矛盾,相比于使用多個變量來分區間表示狀態來說是非常清晰簡練的。State 模式便于增加新的狀態(也需要修改其他狀態的狀態遷移代碼),不便于增加新的 “依賴于狀態的處理”,比如 doAlarm 等,因為一旦增加了,實現了 State 接口的所有狀態都要增加該部分代碼。
同時我們也看到了多面性,比如 SafeFrame 實例實現了 ActionListener 接口和 Context 接口,那么就可以將 new SafeFrame () 對象傳入 fun1 (ActionListener a) 和 fun2 (Context context) 這兩個方法之中,之后這兩個方法對該對象的使用是不同的,權限也不一樣,因此多接口就會產生多面性。狀態模式其實是用了分而治之的思想,將不同的狀態分開來討論,抽取共同性,從而使問題變得簡單。
特別聲明:以上內容(如有圖片或視頻亦包括在內)為自媒體平臺“網易號”用戶上傳并發布,本平臺僅提供信息存儲服務。
Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.