State Machine für MVC-basierte Anwendung

Code-Stücke können hier veröffentlicht werden.
Antworten
glocke
User
Beiträge: 66
Registriert: Mittwoch 23. Februar 2011, 21:18

Hi,
ich habe überlegt, wie man vielleicht eine Anwendung aufbauen könnte, die das MVC-Pattern (zumindest teilweise) umsetzen könnte und dabei eine Art Endlicher Automat (zumindest in Grundzügen) ist. Die "Idee" dahinter ist es, eine Art Grund-Engine für z.B. pygame-basierte Anwendungen zu schreiben. Dabei werden verschiedene "Zustände der Anwendung" (z.B. das Hauptmenü des Spiels, ein Spiel-Laden-Menü, ein Karteneditor usw. als eigenständige Zustände) von einander getrennt und bei in Grundzügen das MVC-Pattern verfolgt. Genau genommen meine ich damit lediglich die Teilung in Model, View und Controller - ohne ein Observer-Pattern usw. zu realisieren. Ich hoffe mein Ziel ist verständlich formuliert :D

Hier mal ein Code-Schnippsel mit den Überlegungen:

Code: Alles auswählen

class Application(object):
    ''' Eine Art State Machine, die den aktuellen Zustand der Anwendung enthält (z.B. Hauptmenü). '''

    def __init__(self, starting_state):
        ''' Initialisiert die State Machine mit einem Anfangszustand.
        @param starting_state: Objekt eines Zustands (class State) '''
        self.state = starting_state
        self.next_state = None

    def set_state(self, next_state):
        ''' Merkt sich den Zustand, der beim nächsten Tick eingenommen wird
        @param next_state: Objekt eines Zustands (class State) '''
        self.next_state = next_state

    def tick(self):
        ''' Haupt-Logik '''
        # hier könnte z.B. ein pygame-Display geleert werden
        if self.next_state:
            # switch to next state
            self.state = self.next_state
            self.next_state = None
        if self.state:
            # do state's model stuff
            self.state.model.tick()
            # do state's view stuff
            self.state.view.tick()
            # handle state's controller stuff
            self.state.tick()
        # und hier könnte z.B. ein pygame-Display geflippt werden

class State(object):
    ''' Ein Zustand, den die State Machine annehmen kann. Diese Klasse repräsentiert den Controller. '''

    def __init__(self, model, view):
        ''' Initialisiert einen Zustand mit zugehörigen Model+ und View-Objekten
        @param model: Objekt für Datenmodell (class BaseModel)
        @param view: Objekt für Datenrepräsentation (class BaseView) '''
        self.model = model
        self.view = view

    def tick(self):
        ''' Haupt-Logik - sollte von Unterklasse überschrieben werden '''
        pass

class BaseModel(object):
    ''' Enthält alle Daten und Manipulationsmethoden für diese, z.B. setFoo, getBar, addCounter. '''
    pass

class ViewModel(object):
    ''' Enthält alle Objekte, die für die Repräsentation der Daten verantwortlich sind, und entsprechende Methoden um diese zu manipulieren.
    Beispielsweise verschiedene pygame.sprite.Sprite-Objekte und Methoden wie moveObject oder focusButton. '''
    pass
Die Frage die ich nun dazu hätte: Ist das so sinnvoll? Wenn nein, was wäre verbesserungswürdig? Wie gesagt: es ist ein grober Entwurf (wie ich die Dinge in meinem Kopf bisher gegliedert habe).

LG Glocke
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

glocke hat geschrieben: Genau genommen meine ich damit lediglich die Teilung in Model, View und Controller - ohne ein Observer-Pattern usw. zu realisieren.
Was genau bringt Dir eine Teilung, ohne dass diese Teile miteinander interagieren? ;-) Denn genau diese einzelnen Pattern (Observer, Composite, Strategy) formen ja erst den zusammengesetzten Pattern namens "MVC".

Bei Deinem Entwurf sind mir einige Dinge unklar: Wieso muss das `Application`-Objekt den nächsten Zustand kennen? Augenscheinlich soll das zur Steuerung der Transitionen dienen - beim klassischen State-Pattern übernehmen das jedoch die einzelnen Status selber. Zudem fehlt mir da irgend wo eine `Collection`. Ein Spiel hat doch zig verschiedene Komponenten, die alle einen eigenen Zustand haben...

Grundsätzlich halte ich es für sinnvoll, vom Spaghetti-Code der gängigen PyGame-Beispiele und Tutorials wegzukommen. Aber ich denke Du hebelst zu viele Elemente auf eine Ebene. Willst Du in Deiner Main-Loop wirklich die GUI, Benutzerinteraktion und sämtliche Spielobjekte gleich behandeln? Ich würde da wohl eine "Zwischenschicht" einbauen und speziell die Spiellogik und die damit verbundenen GUI-Updates von der allgemeinen GUI und den Benutzereingaben abkoppeln. Ein Menü will ich ja irgend wie möglichst immer anklicken können und es sollte nicht mit der Berechnung der Bewegung einer Spielfigur kollidieren ;-)

Evtl. habe ich Deinen Ansatz aber auch falsch verstanden - an dieser Stelle könnte es tatsächlich sinnvoller sein, mit grafischer Modellierung den Ansatz zu veranschaulichen. Es muss ja kein reines UML sein.

Eine kleine Anmerkung noch zum Entwurfscode:

Code: Alles auswählen

    def tick(self):
        ''' Haupt-Logik - sollte von Unterklasse überschrieben werden '''
        pass
Das `pass` solltest Du hier vermeiden. Da Python kein "Interface"-Konzept kennt, kann die Methode der als Basisklasse tatsächlich aufgerufen werden. Hier bietet es sich an, eine `NotImplementedError`-Exception auszulösen. Damit bekommst Du mit, wenn Du ungewollt die Methode der Basisklasse aufrufst.

Generell muss ich gestehen, dass ich auch noch keine PyGame-Applikation gesehen habe, welche ein mir schlüssiges Konzept diesbezüglich aufweist. Vielleicht habe ich mir aber ja auch immer die falschen angeguckt ;-)

PS: Ich vergesse es immer wieder, aber baut nicht ein User hier an einem UI-Toolkit für PyGame? Derjenige hat sich ja bestimmt über dieses Thema fundierte Gedanken gemacht...
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
Antworten