Frage

Grüße, zur Zeit bin ich Refactoring eines meiner Programme, und ich fand ein interessantes Problem.

Ich habe Transitions in einem Automaten. Übergänge haben immer einen Startzustand und einen Endzustand. Einige Übergänge haben eine Bezeichnung, die eine bestimmte Aktion codiert, das bei Traversal ausgeführt werden müssen. Ohne Label bedeutet, dass keine Aktion. Einige Übergänge haben eine Bedingung, die erfüllt werden müssen, um diese Bedingung zu überqueren, wenn kein Zustand ist, der Übergang ist im Grunde ein Epsilon-Übergang in einem NFA und wird ohne Verbrauch eines Eingangssymbols verfahren werden.

Ich brauche die folgenden Operationen:

  • prüfen, ob der Übergang ein Label
  • hat
  • erhalten dieses Label
  • fügen Sie ein Etikett auf einen Übergang
  • prüfen, ob der Übergang hat eine Bedingung
  • erhalten diese Bedingung
  • Prüfung auf Gleichheit

aus den ersten fünf Punkten zu urteilen, das klingt wie ein klarer Dekorateur, mit einem Basenübergang und zwei Dekorateure: Beschriftet und Zustand. Doch dieser Ansatz hat ein Problem: zwei Übergänge berücksichtigt werden gleich, wenn ihre Start-Zustand und End-Zustand gleich sind, die Etiketten an beiden Übergänge gleich sind (oder nicht vorhandenen) und beide Bedingungen sind die gleichen (oder nicht vorhanden) . Mit einem Dekorateur könnte, ich habe zwei Übergänge Beschriftete ( "foo", bedingte ( "bar", Transition ( "baz", "qux"))) und Conditional ( "bar", beschriftet ( "foo", Transition ( "baz “,‚qux‘))), die eine nicht-lokale Gleichheit müssen, das heißt, müssten die Dekorateure alle Daten sammeln und der Übergang muss dieser Vergleich gesammelten Daten auf einer Set-Basis:

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)

Ist das ein sauberer Ansatz? Bin ich etwas fehlt?

Ich bin meistens verwirrt, weil ich dieses Problem lösen kann - mit längeren Klassennamen - kooperative Mehrfachvererbung:

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

die Klasse LabledConditionalTransition verhält sich genau wie erwartet -. Und keinen Code mit drin ist ansprechend und ich weiß nicht, was MI in dieser Größe ist verwirrend

Natürlich wäre die dritte Option, um einfach alles in eine einzigen Übergang Klasse Hammer mit einem Bündel in has_label / has_transition.

So ... Ich bin verwirrt. Bin ich etwas fehlt? Welche Implementierung sieht besser aus? Wie wollen Sie Ähnliche Fälle behandeln, dh Objekte, die wie ein Dekorateur schauen sie umgehen können, aber dann eine solche nicht-lokale Methode kommt herum?

EDIT : die ConditionalTransition-Klasse hinzugefügt. Im Grunde ist dies verhält sich so ähnlich wie der Überzugseinrichtung, minus der Reihenfolge von der Reihenfolge erstellt, die Dekoratore schaffen, die Übergangsprüfungen für Start und Ende ist richtig, ist die LabeledTransition Klasse überprüft Etikett korrekt und ConditionalTransition prüft Zustand ist korrekt zu sein.

War es hilfreich?

Lösung

Ich denke, sie klar, dass niemand wirklich Ihre Frage versteht. Ich würde vorschlagen, es in Zusammenhang setzen und es kürzer zu machen. Als Beispiel hier ist eine mögliche Implementierung des Zustandsmusters in Python, studieren Sie bitte eine Vorstellung zu bekommen.

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

die Ausgabe dieses Programm wäre:

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

Andere Tipps

Aus dem Code, der geschrieben wurde, der einzige Unterschied zwischen Transition und Labeled Transition ist die Rückkehr der get_lable () und has_label (). In diesem Fall können Sie diese beiden eine einzige Klasse komprimieren, die ein Label-Attribut auf Keine setzt und

return self.label is not None

in der has_label () Funktion.

Können Sie den Code für die ConditionalTransition Klasse posten? Ich denke, das wäre es klarer machen.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top