你們好,今天給你們介紹一個新的設計模式,這個設計模式很是重要,在咱們平常的開發工做當中常用。它就是大名鼎鼎的狀態機模式。node
狀態機模式很是適合用在複雜的流程或者是系統當中,能夠方便咱們對系統的某一個狀態進行抽象,這會讓咱們編碼具備更強的可讀性以及延展性。git
首先和你們解釋一下狀態機當中這個狀態的概念,這裏的狀態指的是咱們系統或者是流程當中的某一個狀態。我用我以前作過的一個活動系統來給你們舉一個例子。github
好比咱們如今要在網上舉辦一些活動,而後吸引用戶來參與。可是在用戶來參與活動的過程中其實有不少的狀態須要判斷,好比說咱們首先要判斷用戶是否已經登陸了。若是登陸了,還須要判斷用戶以前是否報名過,若是已經報名了,還須要判斷活動是否開始了等等。web
那麼,咱們就能夠抽象出不少的狀態。好比是否登陸、是否報名、未登陸等等這些都是狀態。這些狀態之間能夠經過一些條件進行轉移,好比在初始狀態當中,經過判斷用戶是否登陸選擇轉移到未登陸狀態或者是報名判斷的狀態上。咱們把這其中的邏輯抽象出來,能夠獲得這麼一張有向無環圖。設計模式
幾乎全部的固定流程均可以抽象出這麼一張圖來,這種圖通常被縮寫成DAG(Directed Acyclic Graph)。若是不用狀態機的話,那麼咱們須要編寫大量的代碼來進行判斷。就拿上述的這個邏輯舉例,咱們須要至少4層if嵌套的邏輯判斷來實現這麼一個流程。app
若是經過if判斷來實現的話,那麼面臨的一個問題就是這個流程是固定的。若是臨時須要改動,那麼必需要修改代碼,而咱們知道無論大小公司,發佈代碼都是有嚴格的規範的,是不能隨意發佈的。而使用狀態機主要解決的就是這個問題,能夠把流程作成可配置的,若是須要臨時修改,只須要修改狀態機的對應配置便可,能夠規避掉代碼層面的修改。編輯器
理解了DAG以後,咱們再來看看狀態機的定義和解釋。flex
狀態機的官方定義是:編碼
The intent of the STATE pattern is to distribute state-specific logic across classes that represent an object’s state. 狀態模式會將與狀態有關的邏輯分佈寫在表明對象狀態的類中url
這句話英文讀起來仍是挺好理解的,中文相對更繞一些。簡而言之,machine是一種抽象的概念,表明某一個流程或者是原理,並非咱們理解的機器。因此狀態機也不是一個機器,它是由多個表明狀態的類組合而成的流程或者說模式。也就是說咱們會把DAG當中的每個節點(狀態)單獨實現成一個類,那麼整個DAG就是一系列狀態類構成的圖。
對於每一個狀態類而言,它們的操做應該都是相似的,就是初始化、執行以及轉移。在一些系統當中,甚至能夠沒有執行只有轉移。既然全部狀態的操做都是相似的,那麼咱們能夠對全部的狀態抽象出統一的接口。這裏咱們多了一個is_end方法,表明某一個狀態是不是整個流程的結束,若是是的話,咱們就不須要繼續轉移了,直接退出便可。
class State:
def __init__(states):
pass
def determine(param):
pass
def operate():
pass
def is_end():
pass
一樣,咱們能夠實現狀態機的類。
class StateMachine:
def __init__():
self.node = StartState()
def init():
self.node = StartState()
def run(param):
while not self.node.is_end():
self.node = self.node.determine(param)
self.node.operate()
因爲狀態之間轉移以及執行的邏輯都被封裝在不一樣的類當中了,因此對於狀態機而言,裏面的邏輯很是簡單,通常也不須要太大的修改。即便整個流程或者是某一個狀態的條件發生變更, 咱們也只須要修改對應節點的代碼便可,並不會影響總體,很是適合用在那些流程常常發生變更的場景。
最後,咱們來看一個狀態機的使用案例。這個案例源於github,是一個將狀態機應用在收音機上的case,具體的細節查看代碼便可。
class State:
def scan(self):
# 模擬收音機的儀表盤,只能一個方向轉動
self.pos += 1
if self.pos == len(self.stations):
self.pos = 0
print('Scanning... Station is {} {}'.format(self.stations[self.pos], self.name))
class AmState(State):
# Am 音頻的類
def __init__(self, radio):
self.radio = radio
self.stations = ['1250', '1380', '1510']
self.pos = 0
self.name = 'AM'
def toggle_amfm(self):
# 轉移到Fm
print('Switching to FM')
self.radio.state = self.radio.fmstate
class FmState(State):
# Fm 音頻類
def __init__(self, radio):
self.radio = radio
self.stations = ['81.3', '89.1', '103.9']
self.pos = 0
self.name = 'FM'
def toggle_amfm(self):
# 轉移到Am
print('Switching to AM')
self.radio.state = self.radio.amstate
class Radio:
# 收音機的總體類,也就是狀態機類
def __init__(self):
self.amstate = AmState(self)
self.fmstate = FmState(self)
self.state = self.amstate
def toggle_amfm(self):
self.state.toggle_amfm()
def scan(self):
self.state.scan()
if __name__ == '__main__':
radio = Radio()
actions = [radio.scan] * 2 + [radio.toggle_amfm] + [radio.scan] * 2
actions *= 2
for action in actions:
action()
整個狀態機的設計模式自己並不複雜,更多的是對這個設計理念和思想的理解,代碼和形式都是表象。
好了,今天的文章就到這裏,衷心祝願你們天天都有所收穫。若是還喜歡今天的內容的話,請來一個三連支持吧~(點贊、關注、轉發)