Logic-Data-View-Controller-Service-Paradigma: Unterschied zwischen den Versionen

aus GlossarWiki, der Glossar-Datenbank der Fachhochschule Augsburg
Zeile 58: Zeile 58:
Folgendes Klassendiagramm zeigt, wie eine Anwendung, die gemäß dem LDVCS-Paradigma implementiert wird, prinzipiell aufgebaut ist.  
Folgendes Klassendiagramm zeigt, wie eine Anwendung, die gemäß dem LDVCS-Paradigma implementiert wird, prinzipiell aufgebaut ist.  


[[Medium:LDVCS 01 Class Diagram .jpg]]
[[Medium:LDVCS 01 Class Diagram.jpg|left|miniatur|977px|'''LDVCS-Klassendiagramm ([http://glossar.hs-augsburg.de/beispiel/tutorium/flex_4/ldvcs/ Umsetzung in Flex 4],
[http://glossar.hs-augsburg.de/webdav/tutorium/flex_4/ldvcs/ SVN-Repository])]]
 


Für jeder der fünf Komponenten (Logic, Data, Model, View. Controller) gibt es ein Interface,
Für jeder der fünf Komponenten (Logic, Data, Model, View. Controller) gibt es ein Interface,

Version vom 23. Dezember 2010, 10:54 Uhr

Definition

Das Logic-Data-View-Controller-Services-Paradigma oder -Pattern, kurz LDVCS, bezeichnet ein Architekturmuster zur Trennung einer Anwendung in drei separate Einheiten: Logic (Logik), Data (Daten), View (Darstellung), Controller (Steuerung) und Service (Service).

Konzept

gerahmt||rechts|LDVCS-Prozess Dieses Paradigma ist eine Verfeinerung des Model-View-Controller-Services-Paradigmas.

Die Modellkomponente des MVCS-Paradigmas übernimmt normalerweise zwei Aufgaben: Die Speicherung der Anwendungsdaten und die Realisierung der Anwendungslogik. (Manchmal übernimmt auch der Controller die Realisierung der Anwendungslogik.) Im LDVCS-Paradigma wird die Modellkomponente in zwei Komponenten aufgeteilt: eine Datenkomponente (Data) und eine Logikkomponente (Logic). Der Controller darf nun nicht mehr direkt schreibend auf die Datenkomponente zugreifen. Dies ist jetzt die Aufgabe der Logikkomponenten (und evtl. der Servicekomponente).

Der LDVCS-Prozess

Beispiel Jump 'n' Run

In einem Jump-'n'-Run-Spiel werden Daten (Data) über die Spielfigur (Position, Laufrichtiung, Geschwindigkeit ...), die Gegner, die Gegenstände etc. gespeichert.

Die View' visualisiert die Elemente des Spiels mit Hilfe von Bildern und Animationen (Walk cyles etc.). Jede Änderung an den Daten hat, sofern sie sich im für den Spieler sichtbaren Bereich befindet, eine Anpassung der View zur Folge.

Der Spieler steuert die Spielfigur mit Hilfe der Tastatur. Jeder Tastendruck wird vom Controller analysiert und zur Manipulation der Spielfigur an die Logik-Komponente (Logic) weitergeleitet.

Man beachte, dass die Logik-Komponente i. Allg. aktiv sein kann: Sie kann die Daten selbstständig, d.h. auch ohne Manipultation durch den Controller verändern. Beispielsweise werden die gegnerischen Figuren, sofern es welche gibt, direkt von der Logik-Komponente gesteuert.

Mit Hilfe einer Service-Komponente (Service) kann das Spiel zu einem Multiuser-Spiel erweitert werden. Die Service-Komponente hat dann zwei Aufgaben:

  1. Die Position des Avatars (d.h. der eigenen Spielfigur) an einen zentralen Server zu übertragen.
  2. Die Postition anderer Spielfiguren und möglicher Gegner vom zentralen Server zu holen und in die eigene Datenkomponente zu schreiben.

Eine weitere typische Aufgabe der Service-Komponente ist es, die Daten-Komponente bei Programmstart zu initialisieren. Zu diesem Zweck sollten die Servic-Komponente eine Initialisierungsmethode implementieren, die vom Hauptprogramm direkt aufgerufen wird, nachdem die Daten- und die Service-Komponete erzeugt wurden.

Modularität

Der große Vorteil des LDVCS-Paradigmas ist die Modularität. Das PrinzipSeparation of Concerns“ wird hierbei bachtet: Jede Aufgabe wird von einer eigenen Komponente bearbeitet.

Ein Jump'n'Run-Spiel beispielsweise, das derartig modular aufgebaut ist, kann sehr leicht an neue Gegebenheiten angepasst werden. Jede der folgenden Änderungen hat lediglich Auswirkungen auf eine der fünf Komponenten:

  1. Änderung der Darstellung (d.h. der View): Die View kann jederzeit durch neue Skins aktualisiert werden. Es ist auch möglich, die 2D-Ansicht des Spiels durch eine Pseudo-3D-Ansicht zu ersetzen. Bei einem Multiuser-Spiel hat sowieso jeder Spieler seine eigene Sicht auf die Szenerie.
  2. Änderung der Spielsteuerung (d.h. des Controllers): Anstelle einer Steuerung der Spielfigur durch die Tastatur kann beispielsweise eine Steuerung der Spielfigur durch eine WiiMote erfolgen.
  3. Änderung der Spiellogik (d.h. der Logikkomponente): Die KI-Engine zur Steuerung der Gegener kann beispielsweise durch eine bessere Engine ersetzt werden.
  4. Änderung der Dateninitialisierung (d.h. der Service-Komponente): Wenn die Dateninitialisierung künfig beispielsweise nicht mehr über XML, sondern über SQL erfolgen soll, muss ledichlich die entsprechende Service-Komponente ausgetauscht werden.
  5. Änderung des Spielservers (d.h. der Service-Komponente): Es ist jederzeit möglich, ein Multi-User-Spiel über einen anderen Server (mit einer anderen Architektur) laufen zulassen.

Lediglich die Datenkomponente wird im Allgemeinen nicht ausgetauscht, sondern höchstens erweitert. Allerdings ist es denkbar, Filter vorzuschalten, die einen Zugriff auf bestimmte Daten erst dann erlauben, wenn beispielsweise ein Login-Vorgang erfolgreich abgschlossen wurde.

Implementierung

Folgendes Klassendiagramm zeigt, wie eine Anwendung, die gemäß dem LDVCS-Paradigma implementiert wird, prinzipiell aufgebaut ist.

left|miniatur|977px|LDVCS-Klassendiagramm ([http://glossar.hs-augsburg.de/beispiel/tutorium/flex_4/ldvcs/ Umsetzung in Flex 4], [http://glossar.hs-augsburg.de/webdav/tutorium/flex_4/ldvcs/ SVN-Repository])


Für jeder der fünf Komponenten (Logic, Data, Model, View. Controller) gibt es ein Interface, das die Methoden und Attribute deklariert, die diese Komponente unterstützt, sowie eine Klasse, die das zugehörige Interface implementiert. Häufig handelt es sich bei derartigen Komponentenklassen sogar um Singleton-Klassen (vgl. Singleton-Pattern). Im Allgemeinen gibt es weitere Komponentenklassen, auf die über die fünf „Haupt-Komponentenklassen“ zugegriffen werden kann.

Darüber hinaus gibt es eine Komponentenklasse Domain, die alle zugehörigen Komponenten erzeugt und initialisiert. Auch zu dieser Klasse gibt es im Allgemeinen nur ein Objekt (Singleton-Pattern).

Durch die Verwendung von Interfaces ist es ganz einfach, eine Kompnentenimplementierung (in der Komponentenklasse Domain) durch eine andere zu ersetzen.

Man beachte, dass jede Komponente alle anderen Komponenten „kennt“, mit denen sie evtl. kommunizieren muss. Die zugehörigen Part-of-Attribute können als Add-only-Attribute implementiert werden. Das heißt, es ist nicht notwendig, dass die Werte dieser Attribute nach der Initialisierung durch die Komponentenklasse Domain noch einmal von einer anderen Komponente gelesen werden müssten.

Abhängig von ihrer jeweiligen Aufgabe haben die verschiedenen Komponenten verschiedene Attribute und erweitern (bzw. implementieren) verschiedene Interfaces:

IDomainData, DomainData
Erweitert das IPublischer-Interface (vgl. Observer-Pattern), d.h. signalisiert Änderungen an andere Komponenten.
Das Dateninterface definiert eine Reihe von Attributen, die von der Logik- und der Service-Komponente manipuliert und von den anderen Komponenten gelesen werden können.
Im Sinne des Interface-Segregation-Prinzips sollte man sogar zwei Interfaces zur Verfügung stellen: Eines, das nur lesenden Zugriff auf die Attribute zulässt, und eines, dass das erste Interface um einen schreibenden Zugriff auf die Attribute erweitert und nur von der Logic- und der Service-Komponente verwendet wird.
Es ist durchaus möglich und wiederum wegen des Interface-Segregation-Prinzips auch sinnvoll mehrere (möglichst unabhängige) Datenkomponenten zu implementieren. Der Zugang zu diesen Komponenten würde dann über die „Haupt-Datenkomponente“ DomainData gewährt werden.
Wegen des von Bertrand Meyer geforderten Prinzips der Modularen Robustheit sollte die Datenkomponente nur diejenigen Daten zur Verfügung stellen, auf die der aktuelle Benutzer auch Zugriff hat. Das heißt, die Daten-Komponente filtert selbstständig Daten (abhängig vom Inhalt anderer Attribute), wenn dies notwendig sein sollte.
IDomainLogic, DomainLogic
Erweitert das IOberserver-Interface (vgl. Observer-Pattern), um über Änderungen an der Datenkomponente informiert zu werden.
Das Logikinterface definiert einie Reihe von Methoden, die von der Controller-Komponente aufgerufen werden können.
Auch hier ist es möglich, mehrere Komponenten-Klassen zu definieren, auf deren Objekte über die Hauptkomponente DomainLogic zugegriffen werden kann.
Die Aufgabe der Logik-Komponente ist es, die Datenkomponente entweder direkt oder indirekt (über die Servicekomponente, i. Allg. asynchron) zu manipulieren.
Diese Manipulation kann auch aktiv, d.h. unabhängig von Methodenaufrufen durch den Controller erfolgen. Beispielsweise kann eine KI-Komponente eine Spielfigur selbstständig steuern.
IDomainController, DomainController
Könnte das IOberserver-Interface (vgl. Observer-Pattern) erweitern, um über Änderungen an der Datenkomponente informiert zu werden (zum Beispiel für Force-Feedback-Aktionen). Dies ist i. Allg. jedoch nicht notwendig.
Das Controller-Interface definiert i. Allg. eine Reihe von Methoden, die von der Viewkomponente aufgerufen werden können. Die Komponente kann aber auch Verbindungen zu anderen Eingabemedien herstellen (wie z.B. Tastatur, USB-Controller etc.), um Benutzer-Aktionen abzufangen und geeignet an die Logik-Komponente weiterzuleiten.
IDomainView, DomainView
Erweitert das IOberserver-Interface (vgl. Observer-Pattern), um über Änderungen an der Datenkomponente informiert zu werden.
Die Viewkomponente „visualisert“ den aktuellen Zustand der Datenkomponente geeignet. Dabei ist der Begriff „visualisieren“ sehr weit gefasst: Auch Audio-Ausgaben, Ausgaben an haptische Geräte wie Braille-Zeilen, Steuerung von Lichtorgeln etc. wird darunter verstanden.
Die Viewkomponente reicht außerdem Benutzereingaben (z.B. Mausklicks auf dem Monitor) an die Controllerkomponente weiter.
Im Sinne des Single responsibility principle's sollten die Visualisierung und die Aktivierung des Controllers allerdings von unterschiedlichen Viewobjekten vorgenommen werden.
IDomainService, DomainService
Erweitert das IOberserver-Interface (vgl. Observer-Pattern), um über Änderungen an der Datenkomponente informiert zu werden.
Diese Erweiterung ist allerdings nur notwendig, wenn die Servicekomponente automatisch Änderungen, die die Datenkomponente signalisiert, an einen Server übertragen soll.
Falls die Logikkomponente die Services zum Laden von Daten aus dem Netz oder zum Speichern von Daten im Netz aktivieren soll, muss die Servicekomponente dagegen einen Satz geeigneter MEthoden zur Verfügung stelln.

Verfeinerung des LDVCS-Prozesses

Genauso wie der MVC-Prozess und der MVCS-Prozess kann auch der LDVCS-Prozess verfeinert werden. Auch hier bietet sich die Aufteilung in Kernawendungen (Domains) und eine Rahmenanwendung (Frame) an, die den Zugang zu den Kernanwendungen steuert. In diesem Fall gibt es mehrere relativ unabhängige LDVCS-Prozesse: Die Rahmenkomponente darf auf zugehörigen Kernkomponenten zugreifen. Der umgekehrte Weg sollte allerdings vermieden werden, damit die Kernanwendungen problemlos in andere Umgebungen integriert werden können.

gerahmt|links|LDVCS-Prozess 2 (mit Trennung in Frame und Domain)  

Beispiel „Spiel mit Highscore-Verwaltung“

Wenn man ein „Spiel mit Highscore-Verwaltung“ realisieren möchte, sollte man zwei unanhängige Kernanwendungen schreiben. Das Spiel selbst und eine spielunabhängige Highscore-Verwaltung. Die Rahmenanwendung verknüpft diese beiden Anwendungen.

Die Rahmenanwendung liest beispielsweise bei Spielende die erreichten Punkte aus dem Spielmodell aus und leitet diese an das Highscore-Modell weiter. Eine weitere Möglichkeit wäre, dass die Rahmenanwendung über die Highscore-Anwendung ermittelt, ob der Spieler schon mindestens fünf Level erfolgreich gespielt hat. Nur in diesem Fall gewährt sie den Zugang zum Trainingsmodus des Spiels.

Quellen


Dieser Artikel ist GlossarWiki-konform.