摘要:很明顯,有有分錢沒有分錢售出糖果糖果售罄四個狀態,同時也對應四個動作投入分錢,退回分錢,轉動曲柄和發放糖果。狀態模式的類圖如下狀態模式是將多個行為封裝在狀態對象中,的行為隨時可委托到其中一個狀態中。
問題:有一個糖果公司需要設計一個糖果售賣機,控制流程如下圖,需要怎么實現?
這是一個狀態圖,每個圓圈都是一種狀態。很明顯,有有25分錢、 沒有25分錢、 售出糖果、 糖果售罄四個狀態,同時也對應四個動作:投入25分錢,退回25分錢,轉動曲柄和發放糖果。
那如何從狀態圖得到真正的代碼呢?
簡單代碼實現如下:
#! -*- coding: utf-8 -*- class GumballMachine: # 找出所有狀態,并創建實例變量來持有當前狀態,然后定義狀態的值 STATE_SOLD_OUT = 0 STATE_NO_QUARTER = 1 STATE_HAS_QUARTER = 2 STATE_SOLD = 3 state = STATE_SOLD_OUT def __init__(self, count=0): self.count = count if count > 0: self.state = self.STATE_NO_QUARTER def __str__(self): return "Gumball machine current state: %s" % self.state def insert_quarter(self): # 投入25分錢 if self.state == self.STATE_HAS_QUARTER: # 如果已經投過 print("You can"t insert another quarter") elif self.state == self.STATE_NO_QUARTER: # 如果沒有投過 self.state = self.STATE_HAS_QUARTER print("You inserted a quarter") elif self.state == self.STATE_SOLD_OUT: # 如果已經售罄 print("You can"t insert a quarter, the machine is sold out") elif self.state == self.STATE_SOLD: # 如果剛剛買了糖果 print("Please wait, we"re already giving you a gumball") def eject_quarter(self): # 退回25分 if self.state == self.STATE_HAS_QUARTER: print("Quarter returned") self.state = self.STATE_NO_QUARTER elif self.state == self.STATE_NO_QUARTER: print("You haven"t inserted a quarter") elif self.state == self.STATE_SOLD: print("Sorry, you alread turned the crank") elif self.state == self.SOLD_OUT: print("You can"t eject, you haven"t inserted") def turn_crank(self): # 轉動曲柄 if self.state == self.STATE_SOLD: print("Turning twice doesn"t get you another gumball") elif self.state == self.STATE_NO_QUARTER: print("You turned but there"s no quarter") elif self.state == self.STATE_SOLD_OUT: print("You turned, but there are no gumballs") elif self.state == self.STATE_HAS_QUARTER: print("You turned...") self.state = self.STATE_SOLD self.dispense() def dispense(self): # 發放糖果 if self.state == self.STATE_SOLD: print("A gumball comes rolling out the slot") self.count -= 1 if self.count == 0: self.state = self.STATE_SOLD_OUT else: self.state = self.STATE_NO_QUARTER elif self.state == self.STATE_NO_QUARTER: print("You need to pay first") elif self.state == self.STATE_SOLD_OUT: print("No gumball dispensed") elif self.state == self.STATE_HAS_QUARTER: print("No gumball dispensed") if __name__ == "__main__": # 以下是代碼測試 gumball_machine = GumballMachine(5) # 裝入5 個糖果 print(gumball_machine) gumball_machine.insert_quarter() # 投入25分錢 gumball_machine.turn_crank() # 轉動曲柄 print(gumball_machine) gumball_machine.insert_quarter() #投入25分錢 gumball_machine.eject_quarter() # 退錢 gumball_machine.turn_crank() # 轉動曲柄 print(gumball_machine) gumball_machine.insert_quarter() # 投入25分錢 gumball_machine.turn_crank() # 轉動曲柄 gumball_machine.insert_quarter() # 投入25分錢 gumball_machine.turn_crank() # 轉動曲柄 gumball_machine.eject_quarter() # 退錢 print(gumball_machine)
這段代碼有幾個問題:
沒有遵守開放-關閉原則
更像是面向過程的設計
狀態轉化被埋藏在條件語句中
未來加入新的需求,需要改動的較多,不易維護,可能會出bug
如何改進呢?
考慮封裝變化,把每個狀態的行為都放在各自的類中,每個狀態只要實現自己的動作,用加入新類的方式來實現新狀態的加入。
定義State 父類,在這個類中,糖果機的每個動作都有一個應對的方法
為機器中的每個狀態實現狀態類,這些類將負責在對應的狀態下進行機器的行為
擺脫舊的條件代碼,將動作委托到狀態類
新的實現代碼如下:
#! -*- coding: utf-8 -*- class State: # 定義state基類 def insert_quarter(self): pass def eject_quarter(self): pass def turn_crank(self): pass def dispense(self): pass class SoldOutState(State): # 繼承State 類 def __init__(self, gumball_machine): self.gumball_machine = gumball_machine def __str__(self): return "sold_out" def insert_quarter(self): print("You can"t insert a quarter, the machine is sold out") def eject_quarter(self): print("You can"t eject, you haven"t inserted a quarter yet") def turn_crank(self): print("You turned, but ther are no gumballs") def dispense(self): print("No gumball dispensed") class SoldState(State): # 繼承State 類 def __init__(self, gumball_machine): self.gumball_machine = gumball_machine def __str__(self): return "sold" def insert_quarter(self): print("Please wait, we"re already giving you a gumball") def eject_quarter(self): print("Sorry, you already turned the crank") def turn_crank(self): print("Turning twice doesn"t get you another gumball") def dispense(self): self.gumball_machine.release_ball() if gumball_machine.count > 0: self.gumball_machine.state = self.gumball_machine.no_quarter_state else: print("Oops, out of gumballs!") self.gumball_machine.state = self.gumball_machine.soldout_state class NoQuarterState(State): # 繼承State 類 def __init__(self, gumball_machine): self.gumball_machine = gumball_machine def __str__(self): return "no_quarter" def insert_quarter(self): # 投幣 并且改變狀態 print("You inserted a quarter") self.gumball_machine.state = self.gumball_machine.has_quarter_state def eject_quarter(self): print("You haven"t insert a quarter") def turn_crank(self): print("You turned, but there"s no quarter") def dispense(self): print("You need to pay first") class HasQuarterState(State): # 繼承State 類 def __init__(self, gumball_machine): self.gumball_machine = gumball_machine def __str__(self): return "has_quarter" def insert_quarter(self): print("You can"t insert another quarter") def eject_quarter(self): print("Quarter returned") self.gumball_machine.state = self.gumball_machine.no_quarter_state def turn_crank(self): print("You turned...") self.gumball_machine.state = self.gumball_machine.sold_state def dispense(self): print("No gumball dispensed") class GumballMachine: def __init__(self, count=0): self.count = count # 找出所有狀態,并創建實例變量來持有當前狀態,然后定義狀態的值 self.soldout_state = SoldOutState(self) self.no_quarter_state = NoQuarterState(self) self.has_quarter_state = HasQuarterState(self) self.sold_state = SoldState(self) if count > 0: self.state = self.no_quarter_state else: self.state = self.soldout_state def __str__(self): return "Gumball machine current state: %s" % self.state def insert_quarter(self): # 投入25分錢 self.state.insert_quarter() def eject_quarter(self): # 退回25分 self.state.eject_quarter() def turn_crank(self): # 轉動曲柄 self.state.turn_crank() self.state.dispense() def release_ball(self): # 發放糖果 print("A gumball comes rolling out the slot...") if self.count > 0: self.count -= 1 if __name__ == "__main__": # 以下是代碼測試 gumball_machine = GumballMachine(5) # 裝入5 個糖果 print(gumball_machine) gumball_machine.insert_quarter() # 投入25分錢 gumball_machine.turn_crank() # 轉動曲柄 print(gumball_machine) gumball_machine.insert_quarter() #投入25分錢 gumball_machine.eject_quarter() # 退錢 gumball_machine.turn_crank() # 轉動曲柄 print(gumball_machine) gumball_machine.insert_quarter() # 投入25分錢 gumball_machine.turn_crank() # 轉動曲柄 gumball_machine.insert_quarter() # 投入25分錢 gumball_machine.turn_crank() # 轉動曲柄 gumball_machine.eject_quarter() # 退錢 print(gumball_machine)
重構后的代碼相對于之前的代碼做了哪些事情呢?
將每個狀態的行為局部話到自己的類中
刪除if 語句
將狀態類對修改關閉,對糖果季類對擴展開放
下圖是剛初始狀態圖示:
上面重構部分代碼使用的就是狀態模式:
定義狀態模式: 狀態模式允許對象在內部狀態改變時改變它的行為,對象看起來好像修改了它的類。
狀態模式的類圖如下:
狀態模式是將多個行為封裝在狀態對象中, context 的行為隨時可委托到其中一個狀態中。當前狀態在不同的狀態對象中改變,以反映出context 內部的狀態,context 的行為也會隨之改變。擴展
如果,現在要在這四個狀態的基礎上再加一個狀態(購買糖果后,有10%的概率再得一個),該如何實現呢?
# 添加WinnerState 類,只有dispense 方法不同,可以從SoldState 類繼承 class WinnerState(SoldState): def __str__(self): return "winner" def dispense(self): print("You"re a WINNER! You get two gumballs for your quarter") self.gumball_machine.release_ball() if gumball_machine.count == 0: self.gumball_machine.state = self.gumball_machine.soldout_state else: self.gumball_machine.release_ball() if gumball_machine.count > 0: self.gumball_machine.state = self.gumball_machine.no_quarter_state else: print("Oops, out of gumballs!") self.gumball_machine.state = self.gumball_machine.soldout_state # 修改turn_crank 方法 class HasQuarterState(State): ... def turn_crank(self): print("You turned...") winner = random.randint(0, 9) if winner == 4 and self.gumball_machine.count > 1: # 如果庫存大于 1 并且隨機數等于4(可以是0到9任意值) self.gumball_machine.state = self.gumball_machine.winner_state else: self.gumball_machine.state = self.gumball_machine.sold_state # 在 GumballMachine 中初始化 class GumballMachine: def __init__(self, count=0): self.count = count # 找出所有狀態,并創建實例變量來持有當前狀態,然后定義狀態的值 ... self.winner_state = WinnerState(self) ...總結
狀態模式允許一個對象給予內部狀態而擁有不同的行為
狀態模式用類代表狀態
Context 會將行為委托給當前狀態對象
通過將每狀態封裝進一個類,把改變局部化
狀態裝歡可以由State 類或Context 類控制
使用狀態模式會增加類的數目
狀態類可以被多個Context 實例共享
本文例子來自《Head First 設計模式》。
最后,感謝女朋友支持和包容,比??
也可以在公號輸入以下關鍵字獲取歷史文章:公號&小程序 | 設計模式 | 并發&協程
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/42910.html
摘要:在程序設計中,觀察者模式通常被定義為觀察者模式定義了對象之間的一對多依賴,這樣一來,當一個對象改變狀態是,它的所有依賴者都會收到通知并自動更新。事件扮演發布者的角色,監聽者則扮演觀察者的角色。 題目:現在你有一個數字,默認格式化程序是以十進制格式展示此數值,但需要提供一個功能,這個程序要支持添加/注冊更多的格式化程序(比如:添加一個十六進制格式化程序和一個二進制格式化程序)。每次數值...
摘要:什么是狀態模式狀態模式對象行為是基于狀態來改變的。原文地址設計模式手冊之狀態模式優缺點優點封裝了轉化規則,對于大量分支語句,可以考慮使用狀態類進一步封裝。 1. 什么是狀態模式? 狀態模式:對象行為是基于狀態來改變的。 內部的狀態轉化,導致了行為表現形式不同。所以,用戶在外面看起來,好像是修改了行為。 Webpack4系列教程(17篇) + 設計模式手冊(16篇):GitHub地址 博...
摘要:什么是狀態模式狀態模式對象行為是基于狀態來改變的。原文地址設計模式手冊之狀態模式優缺點優點封裝了轉化規則,對于大量分支語句,可以考慮使用狀態類進一步封裝。 1. 什么是狀態模式? 狀態模式:對象行為是基于狀態來改變的。 內部的狀態轉化,導致了行為表現形式不同。所以,用戶在外面看起來,好像是修改了行為。 Webpack4系列教程(17篇) + 設計模式手冊(16篇):GitHub地址 博...
摘要:本篇主要講述中使用函數來實現策略模式和命令模式,最后總結出這種做法背后的思想。 《流暢的Python》筆記。本篇主要講述Python中使用函數來實現策略模式和命令模式,最后總結出這種做法背后的思想。 1. 重構策略模式 策略模式如果用面向對象的思想來簡單解釋的話,其實就是多態。父類指向子類,根據子類對同一方法的不同重寫,得到不同結果。 1.1 經典的策略模式 下圖是經典的策略模式的U...
摘要:進程和線程究竟是什么東西傳統網絡服務模型是如何工作的協程和線程的關系和區別有哪些過程在什么時間發生在剛剛結束的上海站,來自七牛云存儲的高級工程師許智翔帶來了關于的分享中的進程線程協程同步異步回調。使用紅黑樹管理就緒隊列。 進程和線程究竟是什么東西?傳統網絡服務模型是如何工作的?協程和線程的關系和區別有哪些?IO過程在什么時間發生? 在剛剛結束的 PyCon2014 上海站,來自七牛云...
摘要:作者按每天一個設計模式旨在初步領會設計模式的精髓,目前采用和兩種語言實現。享元模式提醒我們將一個對象的屬性劃分為內部和外部狀態。 作者按:《每天一個設計模式》旨在初步領會設計模式的精髓,目前采用javascript和python兩種語言實現。誠然,每種設計模式都有多種實現方式,但此小冊只記錄最直截了當的實現方式 :) 個人技術博客-godbmw.com 歡迎來玩! 每周至少 1 篇原創...
閱讀 1877·2021-11-19 09:40
閱讀 2594·2021-08-30 09:46
閱讀 2177·2021-08-03 14:01
閱讀 2648·2019-08-30 10:54
閱讀 1197·2019-08-29 16:38
閱讀 1440·2019-08-29 11:02
閱讀 2536·2019-08-28 18:16
閱讀 1679·2019-08-28 18:09