2017-06-20 80 views
3

假設我有以下代碼與類實例調用方法的參數在Python

IDLE = 0 
STARTED = 1 
STOPPED = 2 
ERRORED = 3 
# additional states as needed 

class StateMachine: 
    def __init__(self) 
     self.state = IDLE 

    def start(self): 
     self.state = STARTED 
     # do something 

    def stop(self): 
     self.state = STOPPED 
     # do something 

    def reset(self): 
     self.state = IDLE 
     # do something 

我們目前的接口允許客戶端通過闡明期望的目標狀態改變實例的狀態,在這一點上,我們運行某些驗證檢查以及適當的方法。理想情況下,我希望保持所需目標狀態的字典映射到正確的方法,以避免大量和無意義的if語句塊。即

if target_state = STARTED: 
    instance.start() 
elif target_state = STOPPED: 
    instance.stop() 
... 

但我不確定下面的解決方案是否被認爲是好的做法或不(它使用的實例作爲ARG感覺從類有點怪的調用方法)。

state_mapping = { 
    IDLE: StateMachine.reset, 
    STARTED: StateMachine.start, 
    .... 
} 

,然後調用使用:

action = state_mapping[target_state] 
action(instance) 
.... 

有什麼想法?

+0

您是否嘗試過使用'lambda'表達式? –

+0

我認爲解決方案是可以的。也許你應該考慮基準測試,看看什麼時間更有效率。如果效率不是問題,可讀性應該是。我個人認爲'如果'elif'' elif''else'解決方案更具可讀性 - 即使它有點無聊。 – ChickenFeet

+0

還有另一種方法,它有一個整體StateMachine類,然後是每個狀態的子類,如StateMachineStopped,StateMachineStarted。你用'self .__ class__ = StateMachineStopped'方法來回切換。例如,請參閱https://stackoverflow.com/questions/13280680/how-dangerous-is-setting-self-class-to-something-else/24463654#24463654。 –

回答

2

不那麼怪異。

但是,唯一需要牢記的是action是一個未綁定的方法,在對方法調用進行初看時可能不是很明顯;除非我直接知道該字典是如何定義的。

我覺得更可讀的替代方法是從實例調用方法:

state_mapping = { 
    IDLE: "reset", 
    STARTED: "start", 
    .... 
} 

action = state_mapping[target_state] 
getattr(instance, action)() 

這同樣會提高可讀性的情況下,當方法需要多個參數。

+0

感謝您的反饋意見,我曾考慮過這樣做,但在兩種方法之間有點分裂。現在你提到了可讀性,用getattr代替它是有道理的。 – Andy

1

另一種選擇。

由於你的類被稱爲「StateMachine」,也許它應該有一個方法來執行狀態改變?

在這種情況下,您可以使用綁定方法在地圖

class StateMachine: 
    ... 

    def ChangeState(self, target): 
     state_mapping = { IDLE: self.reset, STARTED: self.start, ... } 
     state_mapping[target]() 

您可能希望處理無效的目標狀態,還是讓它養KEY_ERROR例外。

相關問題