こんにちは、現在、プログラムの 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 は条件が正しいかどうかをチェックします。