2008-09-24 73 views
2

問候,目前我正在重構我的一個程序,並且我發現了一個有趣的問題。如何實現具有非本地平等的裝飾器?

我有一個自動機的轉換。轉換總是有一個開始狀態和一個結束狀態。一些轉換有一個標籤,它編碼一個必須在遍歷時執行的Action。沒有標籤意味着沒有行動。有些轉換有一個條件,爲了遍歷這個條件必須滿足條件,如果沒有條件,轉換基本上是一個NFA中的ε-轉換並且將在不消耗輸入符號的情況下被遍歷。

我需要以下操作:

  • 檢查如果過渡有一個標籤
  • 得到這個標籤
  • 添加標籤的過渡
  • 檢查如果過渡有一個條件
  • 得到這個條件
  • 檢查等號

從前五點看,這聽起來像一個清晰的裝飾器,有一個基本過渡和兩個裝飾器:標籤和條件。但是,這種方法存在一個問題:如果兩個轉換的起始狀態和結束狀態相同,兩個轉換的標籤相同(或不存在)並且兩個條件相同(或不存在),則認爲兩個轉換相等。 。使用裝飾器,我可能會有兩個轉換標記(「foo」,條件(「bar」,轉換(「baz」,「qux」)))和條件(「bar」,標記(「foo」,轉換(「baz 」,‘qux’))),這需要一個非本地的平等,也就是裝飾將需要收集所有數據和轉型必須比較該收集的一組類數據:

class Transition(object): 
    def __init__(self, start, end): 
     self.start = start 
     self.end = end 
    def get_label(self): 
     return None 
    def has_label(self): 
     return False 
    def collect_decorations(self, decorations): 
     return decorations 
    def internal_equality(self, my_decorations, other): 
     try: 
      return (self.start == other.start 
        and self.end == other.end 
        and my_decorations = other.collect_decorations()) 
    def __eq__(self, other): 
     return self.internal_equality(self.collect_decorations({}), other) 

class Labeled(object): 
    def __init__(self, label, base): 
     self.base = base 
     self.label = label 
    def has_label(self): 
     return True 
    def get_label(self): 
     return self.label 
    def collect_decorations(self, decorations): 
     assert 'label' not in decorations 
     decorations['label'] = self.label 
     return self.base.collect_decorations(decorations) 
    def __getattr__(self, attribute): 
     return self.base.__getattr(attribute) 

是這是一個乾淨的方法?我錯過了什麼嗎?

我主要是困惑,因爲我可以解決這個問題 - 較長的類名 - 使用協作多重繼承:

class Transition(object): 
    def __init__(self, **kwargs): 
     # init is pythons MI-madness ;-) 
     super(Transition, self).__init__(**kwargs) 
     self.start = kwargs['start'] 
     self.end = kwargs['end'] 
    def get_label(self): 
     return None 
    def get_condition(self): 
     return None 
    def __eq__(self, other): 
     try: 
      return self.start == other.start and self.end == other.end 
     except AttributeError: 
      return False 

class LabeledTransition(Transition): 
    def __init__(self, **kwargs): 
     super(LabeledTransition).__init__(**kwargs) 
     self.label = kwargs['label'] 
    def get_label(self): 
     return self.label 
    def __eq__(self): 
     super_result = super(LabeledTransition, self).__eq__(other) 
     try: 
      return super_result and self.label == other.label 
     except AttributeError: 
      return False 

class ConditionalTransition(Transition): 
    def __init__(self, **kwargs): 
     super(ConditionalTransition, self).__init__(**kwargs) 
     self.condition = kwargs['condition'] 

    def get_condition(self): 
     return self.condition 

    def __eq__(self, other): 
     super_result = super(ConditionalTransition, self).__eq__(other) 
     try: 
      return super_result and self.condition = other.condition 
     except AttributeError: 
      return False 

# ConditionalTransition about the same, with get_condition 
class LabeledConditionalTransition(LabeledTransition, ConditionalTransition): 
    pass 

類LabledConditionalTransition行爲完全如預期 - 且在那裏沒有代碼是有吸引力和我不要在這個大小上讓MI令人困惑。

當然,第三種選擇是將所有內容都打包成一個包含has_label/has_transition的轉換類。

所以......我很困惑。我錯過了什麼嗎?哪個實現看起來更好?你如何處理類似的情況,也就是說,看起來像裝飾者的對象可以處理它們,但是,那麼這種非本地方法會出現嗎?

編輯: 添加了ConditionalTransition類。基本上,這種行爲類似於裝飾器,減去創建裝飾器順序所創建的順序,開始和結束正確的轉換檢查,LabeledTransition類檢查標籤是否正確以及ConditionalTransition檢查條件是否正確。

+0

我看來像你正在嘗試編寫Java代碼在Python。 – hop 2008-09-30 22:43:23

回答

2

我認爲很清楚,沒有人真正理解你的問題。我會建議把它放在上下文中,並縮短它。作爲一個例子,下面是python中狀態模式的一個可能的實現,請研究它以獲得一個想法。

class State(object): 
    def __init__(self, name): 
     self.name = name 

    def __repr__(self): 
     return self.name 

class Automaton(object): 
    def __init__(self, instance, start): 
     self._state = start 
     self.transitions = instance.transitions() 

    def get_state(self): 
     return self._state 

    def set_state(self, target): 
     transition = self.transitions.get((self.state, target)) 
     if transition: 
      action, condition = transition 
      if condition: 
       if condition(): 
        if action: 
         action() 
        self._state = target 
      else: 
       self._state = target 
     else: 
      self._state = target 

    state = property(get_state, set_state) 

class Door(object): 
    open = State('open') 
    closed = State('closed') 

    def __init__(self, blocked=False): 
     self.blocked = blocked 

    def close(self): 
     print 'closing door' 

    def do_open(self): 
     print 'opening door' 

    def not_blocked(self): 
     return not self.blocked 

    def transitions(self): 
     return { 
      (self.open, self.closed):(self.close, self.not_blocked), 
      (self.closed, self.open):(self.do_open, self.not_blocked), 
     } 

if __name__ == '__main__': 
    door = Door() 
    automaton = Automaton(door, door.open) 

    print 'door is', automaton.state 
    automaton.state = door.closed 
    print 'door is', automaton.state 
    automaton.state = door.open 
    print 'door is', automaton.state 
    door.blocked = True 
    automaton.state = door.closed 
    print 'door is', automaton.state 

這個PROGRAMM的輸出將是:

door is open 
closing door 
door is closed 
opening door 
door is open 
door is open 
0

從發佈的代碼中,Transition和Labeled Transition之間的唯一區別是get_lable()和has_label()的返回值。在這種情況下,您可以壓縮這兩個單類設置在has_label()函數標籤屬性爲None,

return self.label is not None 

你可以發佈ConditionalTransition類的代碼嗎?我認爲這會更清楚。

相關問題