7.2 Konzepte 

Das Konzept eines objekt-relationalen Mappings ist weit verbreitet in der objektorientierten Programmierung. Bevor Sie den Mechanismus der eZ Components für diesen Zweck kennenlernen, wollen wir einige grundlegende Vorgehensweisen in dieser Richtung vorstellen und anschließend die Gedanken hinter PersistentObject verdeutlichen.
7.2.1 Active Record 

Das wohl bekannteste Entwurfsmuster zur Implementierung eines ORM-Mechanismus trägt den Namen Active Record. In diesem Entwurfsmuster werden die Modell-Objekte selbst mit Methoden ausgestattet, welche den Zugriff auf die Datenbank ermöglichen. So enthält eine Modell-Klasse typischerweise Methoden zum Abspeichern des Modells und zum Laden eines bestimmten Datensatzes aus der Datenbank. Zusätzlich werden häufig Methoden implementiert, die das Auffinden verbundener Objekte ermöglichen. So würde im GP-Blog die Klasse ezcBlogEntry Methoden wie save(), update() und delete() enthalten, aber auch getComments() zum Auffinden der Kommentare, die zu einem Eintrag abgegeben wurden.
In vielen Fällen enthält eine Modell-Klasse außerdem statische Methoden, die dem Auffinden verschiedener Mengen dieser Klasse dienen. So könnte die Eintragsklasse eine Methode namens getLatestPosts() enthalten, welche die zehn aktuellsten Beiträge aus der Datenbank lädt. Generell sind der Ansatz des Active-Record-Entwurfsmusters, die mit einem Modell-Objekt verbundene Speicherlogik und gegebenenfalls weitere Applikationslogik direkt an das Objekt zu binden. Mehr zum Active Record Pattern können Sie dem Buch von Martin Fowler et al. entnehmen. [Martin Fowler, David Rice, Matthew Foemmel, Patterns of Enterprise Application Architecture, Addison-Wesley Longman, Amsterdam 2003, S. 160. ]
Die Vorteile des Active-Record-Musters liegen in der Zentralisierung der Methoden zu einem Objekt. Alle Manipulationsmöglichkeiten eines Modells finden sich direkt am Objekt selbst. In den meisten Implementierungen dieses Entwurfsmusters wird eine gemeinsame Basisklasse für alle Modelle verwendet, welche die gängigsten Methoden, wie das Speichern und Löschen, generisch für alle Daten-Klassen implementiert. Problematisch kann dieser Ansatz an zwei Stellen werden: Zum einen ist es möglich, dass Ihre Modell-Klassen mit wachsender Projektkomplexität in unermessliche und vor allem unwartbare Größen wachsen. Zum anderen stört die Erweiterung einer gemeinsamen Basisklasse die eigentliche Intention der Objektorientierung, möglichst reale Beziehungen zwischen den Objekten zu modellieren, was bei der Ableitung von einer Klasse, die lediglich das Speichern in einer Datenbank implementiert, nicht gegeben ist.
7.2.2 Row Data Gateway 

Einen anderen Ansatz verfolgt hingegen das EntwurfsmusterRow Data Gateway. [Ibid, S. 152 ] In diesem Pattern wird die Trennung der Applikationslogik von der Speicherlogik und der Modell-Klasse selbst empfohlen. Zu jeder Modell-Klasse wird eine sogenannte Finder-Klasse implementiert, die dem Auffinden von Objekten dient. Hier würde dann die Methode getLatestPosts() residieren. Zusätzlich wird empfohlen, für jedes Modell eine sogenannte Gateway-Klasse zu implementieren, welche die eigentliche Speicherlogik implementiert. Auf dieses Gateway greift sowohl die Applikationslogik zu, um die rudimentären Lade- und Speicheroperationen auszuführen, als auch die Finder-Klasse, welche die bereitgestellten Suchmethoden über das Gateway abwickelt.
Auch dieser Ansatz hat sowohl Vor- als auch Nachteile: Es wird eine strikte logische Trennung zwischen der Applikationslogik, der Speicherlogik und dem Modell selbst vorgenommen und die objektorientierte Vererbung der Modell-Klassen wird nicht gestört. Allerdings erhält man so mindestens drei Klassen für jedes Modell, was bei komplexeren Vererbungshierarchien mit nur einfachen Zugriffsstrukturen schnell zu einem wahren Wust von Klassen führen kann.
7.2.3 Persistent Object 

Bei dem Begriff Persistent Object handelt es sich nicht um ein bestimmtes Entwurfsmuster, was auch ein Grund war, diesen Namen für die Komponente in eZ Components zu wählen. Der Begriff beschreibt lediglich den Vorgang, wie ein Objekt zur Realisierung von Persistenz zwischen beispielsweise zwei HTTP-Requests gespeichert wird.
Die PersistentObject-Komponente zwingt Sie nicht dazu, Ihre Anwendung nach einem bestimmten Muster umzusetzen, sondern überlässt die Entscheidung über geeignete Strukturen komplett Ihnen, je nach Anforderungen Ihres Projekts. Lediglich die benötigten Funktionalitäten wie Laden, Speichern und Suchen werden von der Komponente zentral zur Verfügung gestellt und können beliebig in die Strukturen Ihres Projekts eingebettet werden. Die Erweiterung einer gemeinsamen Basisklasse ist nicht notwendig, ebenso wenig die Implementierung von Zugriffsklassen, wie es das Row-Data-Gateway-Pattern empfiehlt.
Im Folgenden werden wir keines der beiden gezeigten Patterns benutzen, sondern lediglich den Zugriff auf PersistentObject direkt aus der Applikationslogik heraus durchführen. Für kleine Projekte ist dieser Ansatz durchaus ausreichend. Die Erfahrung zeigt jedoch, dass auch kleine Projekte schnell umfangreich werden können. Wir empfehlen deshalb, eine für Ihr Projekt geeignete Struktur zur Realisierung der Persistenz zu wählen und diese anhand von PersistentObject zu implementieren. Ob Sie sich dabei für eines der vorgestellten Muster entscheiden, ein anderes Pattern zu Rate ziehen oder eine eigene Idee verwenden, bleibt ganz Ihnen überlassen.




Ihre Meinung






