2

こんにちは、現在、プログラムの 1 つをリファクタリングしていて、興味深い問題を発見しました。

オートマトンにトランジションがあります。遷移には常に開始状態と終了状態があります。一部のトランジションには、トラバーサル時に実行する必要がある特定のアクションをエンコードするラベルがあります。ラベルがないということは、アクションがないことを意味します。一部の遷移には条件があり、この条件をトラバースするために満たす必要があります。条件がない場合、遷移は基本的に NFA のイプシロン遷移であり、入力シンボルを消費せずにトラバースされます。

次の操作が必要です。

  • トランジションにラベルがあるかどうかを確認する
  • このラベルを入手
  • トランジションにラベルを追加する
  • 遷移に条件があるかどうかを確認する
  • この状態になる
  • 等しいかどうかを確認する

最初の 5 つのポイントから判断すると、これは明確なデコレーターのように思えます。基本遷移と 2 つのデコレーター (Labeled と Condition) があります。ただし、このアプローチには問題があります。開始状態と終了状態が同じで、両方の遷移のラベルが同じ (または存在しない) で、両方の条件が同じ (または存在しない) 場合、2 つの遷移は等しいと見なされます。 . デコレーターを使用すると、2 つの遷移 Labeled("foo", Conditional("bar", Transition("baz", "qux"))) と Conditional("bar", Labeled("foo", Transition("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 が混乱することはありません。

もちろん、3 番目のオプションは、すべてを 1 つのトランジション クラスにまとめて、一連の has_label/has_transition にすることです。

だから...私は混乱しています。何か不足していますか?どちらの実装が見栄えがしますか? 同様のケース、つまり、Decorator で処理できるように見えるオブジェクトをどのように処理しますか?

EDIT : ConditionalTransition クラスを追加しました。基本的に、これはデコレータのように動作しますが、デコレータを作成する順序によって作成された順序を差し引いたものです。トランジションは開始と終了が正しいかどうかをチェックし、LabeledTransition クラスはラベルが正しいかどうかをチェックし、ConditionalTransition は条件が正しいかどうかをチェックします。

4

2 に答える 2

2

誰もあなたの質問を本当に理解していないことは明らかだと思います。文脈に合わせて短くすることをお勧めします。例として、Python での状態パターンの可能な実装の 1 つを次に示します。アイデアを得るために調べてください。

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

このプログラムの出力は次のようになります。

door is open
closing door
door is closed
opening door
door is open
door is open
于 2008-10-20T17:53:19.683 に答える
0

投稿されたコードによると、Transition と Labeled Transition の唯一の違いは、get_lable() と has_label() の戻り値です。その場合、ラベル属性を None に設定する単一のクラスとこれら 2 つを圧縮できます。

return self.label is not None

has_label() 関数で。

ConditionalTransitionクラスのコードを投稿できますか? これで分かりやすくなると思います。

于 2008-09-24T15:52:11.123 に答える