python設計模式【9】-狀態模式

Rnan-prince發表於2020-11-27

定義狀態設計模式

行為模式關注的是物件的響應性。它們通過物件之間的互動以實現更強大的功能。狀態設計模式是一種行為設計模式,有時也被稱為狀態模式物件。在此模式中,一個物件可以基於其內部狀態封裝多個行為。狀態模式也可以看作是在執行時改變物件行為的一種方式。

狀態設計模式允許物件在其內部狀態變化時改變其行為。這看起來就像物件本身已經改變了它的類一樣。狀態設計模式常用於開發有限狀態機,並幫助協調狀態處理操作。

理解狀態設計模式

狀態設計模式的三個主要參與者:

1、State:這被認為是封裝物件行為的介面。這個行為與物件的狀態相關聯。

2、ConcreteState:這是實現State介面的子類。ConcreteState實現物件的特定狀態相關聯的實際行為

3、Context:這定義了客戶感興趣的介面。Context還維護一個ConcreteState子類的例項,該子類在內部定義了物件的特定狀態的實現

下面我們來考察帶有上述3個參與者的狀態設計模式的結構程式碼實現:

from abc import ABCMeta, abstractmethod
 
 
class State(metaclass=ABCMeta):
    @abstractmethod
    def handle(self):
        pass
 
 
class ConcreteStateA(State):
    def handle(self):
        print("ConcreteStateA")
 
 
class ConcreteStateB(State):
    def handle(self):
        print("ConcreteStateB")
 
 
class Context(State):
    def __init__(self):
        self.state = None
 
    def get_state(self):
        return self.state
 
    def set_state(self, state):
        self.state = state
 
    def handle(self):
        self.state.handle()
 
 
context = Context()
stateA = ConcreteStateA()
stateB = ConcreteStateB()
 
context.set_state(stateA)
context.handle()

狀態設計模式的簡單示例

下面的程式碼實現電視遙控器的開關按鈕:

from abc import abstractmethod, ABCMeta
 
 
class State(metaclass=ABCMeta):
    @abstractmethod
    def do_this(self):
        pass
 
 
class StartState(State):
    def do_this(self):
        print("TV on")
 
 
class StopState(State):
    def do_this(self):
        print("TV off")
 
 
class TVContext(State):
    def __init__(self):
        self.state = None
 
    def set_state(self, state):
        self.state = state
 
    def get_state(self):
        return self.state
 
    def do_this(self):
        self.state.do_this()
 
 
context = TVContext()
context.get_state()
 
start = StartState()
stop = StopState()
 
context.set_state(stop)
context.do_this()

狀態設計模式簡單示例2

例如一個計算機系統,它可以有多個狀態;如開機、關機、掛起或休眠。現在想利用狀態設計模式來表述這些狀態;

首先從ComputerState介面開始:

1、state應定義兩個屬性,它們是name和allowed。屬性name表示物件的狀態,而屬性allowed是定義允許進入狀態的物件的列表

2、state必須定義一個switch()方法,由它來實際改變物件的狀態

class ComputerState(object):
    name = 'state'
    allowed = []
 
    def switch(self, state):
        if state.name in self.allowed:
            print('Current:', self, '=>switched to new state', state.name)
        else:
            print('Current:', self, '=>switched to', state.name, 'not possible')
 
    def __str__(self):
        return self.name

下面實現State介面的ConcreteState,我們定義了四個狀態

1、 On:這將開啟計算機。這時候允許的狀態是Off、Suspend和Hibernate。

2、Off:這將關閉計算機。這時候允許的狀態只有On

3、Hibernate:該狀態將計算機置於休眠模式。當計算機處於這種狀態時,只能執行開啟操作

4、Suspend:該狀態將使計算機掛起,一旦計算機掛起,就可以執行開啟操作

class Off(ComputerState):
    name = 'off'
    allowed = ['on']
 
 
class On(ComputerState):
    name = 'on'
    allowed = ['off', 'suspend', 'hibernate']
 
 
class Suspend(ComputerState):
    name = 'suspend'
    allowed = ['on']
 
 
class Hibernate(ComputerState):
    name = 'hibernate'
    allowed = ['on']

現在考慮context類,上下文需要做兩個主要的事情:

1、__init__():該方法定義了計算機的基本狀態。

2、change():該方法將更改物件的狀態,但是行為的實際更改是由ConcreteState類實現的

class Computer(object):
    def __init__(self, model='HP'):
        self.model = model
        self.state = Off()
        
    def change(self, state):
        self.state.switch(state)

以下是客戶端的程式碼:

if __name__ == "__main__":
    comp = Computer()
    comp.change(On)
    comp.change(Off)
 
    comp.change(On)
    comp.change(Suspend)
    comp.change(Hibernate)
    comp.change(On)
    comp.change(Off)

狀態模式的優缺點

優點:

1、在狀態設計模式中,物件的行為是其狀態的函式結果,並且行為在運動時根據狀態而改變。這消除了if/else或switch/case條件邏輯的依賴。

2、使用狀態模式,實現多型行為的好處顯而易見的,並且更易於新增狀態來支援額外的行為

3、狀態設計還提高了聚合性,因為特定於狀態的行為被聚合到ConcreteState類中,並且放置在程式碼中的同一個地方

4、使用狀態設計模式,通過只新增一個ConcreteState類來新增行為是非常容易的。因此,狀態模式不僅改善了擴充套件應用程式行為時的靈活性,而且全面提高了程式碼的可維護性。

缺點:

1、類爆炸:由於每個狀態都需要在ConcreteState的幫助下定義,因此我們可能導致建立了太多功能比較單一的類。我們不妨考慮有限狀態機的情況——如果有許多狀態,但是每個狀態與另一個狀態沒有太大的不同,我們仍然需要將它們寫成單獨的ConcreteState類。這即增加了程式碼量,又使得狀態機構更加難以審查。

2、隨著每個新行為的引入,Context類都需要進行相應的更新處理每個行為。這使得上下文行為更容易受到每個新的行為的影響。


參考:

《python設計模式》(第2版)https://www.epubit.com/

相關文章