Einfaches Objekt-Beziehungen
Business-Objekte wie um sich selbst und ihren Beziehungen verfügbar zu machen. In diesem Artikel zeige ich Ihnen wie.
Einfaches Objekt-Beziehungen
Im letzten Artikel haben wir uns wie die klassische Lager, Bestellungen und der Kunden-Anforderung als drei separate Geschäftsobjekte jeder Aufdeckung ihres Staates durch klar definierte Eigenschaften modelliert werden könnte. Obwohl diese Objekte nun als verwendet werden konnte-ist (obwohl in sehr begrenztem Umfang - wir haben nicht noch definiert, wie ihre Informationen persistent machen!), ihnen fehlt jede Konzept von Beziehungen. Mit anderen Worten, wie können wir wissen die Kunden platziert eine Bestellung, bzw. welche StockItem?
Es ist einleuchtend, zu diesem Zeitpunkt innezuhalten und nachzudenken, wie dies traditionell in einer nicht-OO, datenorientierte Mode behandelt werden würde. Normalerweise würde ein Datenbankeintrag, darstellt die Reihenfolge zwei zusätzliche Feldern speichern einen Fremdschlüssel der Tabelle Kunden, und eine andere auf die StockItem-Tabelle verfügbar. Einer der Mängel dieses Ansatzes hat bereits bewiesen: alle Datenbankfelder ausgesetzt sind, im gleichen Maße; Es gibt kein Konzept für ein Feld als 'Privat' als die andere. Natürlich ist es möglich, dies zu einem gewissen Grad über einen Datenbank-View auszudrücken, aber bei den raw-Daten können nicht Ebene Felder namentlich in Bezug auf die Sichtbarkeit oder Rolle außer unterschieden werden und dem Weg-Wahnsinn liegt.
Nun betrachten Sie wir, wie wir Informationen über den Kunden zugreifen, die einen gegebenen Reihenfolge in diesem traditionellen Modell aufgegeben würde. Vorausgesetzt, dass wir die Informationen über die Reihenfolge, in eine Art von Dataset (vielleicht TQuery) haben, würden wir den Wert der das Fremdschlüsselfeld Kunden, erstellen Sie eine neue Abfrage auswählen aus der Customer-Tabelle basierend auf diesem Wert und untersuchen Sie dann die zurückgegebenen Daten. Hinweis: Dies ist eigentlich ziemlich viel Code zu schreiben, erfordert mindestens ein lokales Objekt (Kunden-Dataset) konstruiert werden, und solchen Code wuchert schnell, wenn wir auf die Lagerposition oder andere ähnliche Datenelemente zugreifen müssen. Eine Alternative zu diesem Ansatz besteht darin, alle Daten in einer einzigen Abfrage mit einem Multi-Tisch-Join auswählen. Dies überwindet die Menge an Code geschrieben werden, sondern stellt ein weiteres Problem - das harte Kodierung der Datenbeziehungen innerhalb der Abfragezeichenfolge. In etwas anderes als eine triviale Anwendung solcher Ausdrücke werden an vielen verschiedenen Orten im ganzen - wiederholt, und es ist erwähnenswert, dass der Compiler, nichts tun kann zu helfen, die Richtigkeit solcher Abfragen. Wenn Sie Datenbank-Grundlagen (vielleicht ändern, des Namens oder der Typ der das Fremdschlüsselfeld in einer Tabelle) ändern, ist es notwendig anwendungsweiten Suche und Techniken, um Vorkommnisse zu finden, die Aktualisierung möglicherweise ersetzen. In dieser Situation ist es durchaus möglich, dass einige selten genutzte Form werden durch das Netz fallen und behalten einen veraltet-Verweis auf ein Feld, das nicht mehr existiert. Dies ist ein Laufzeitfehler auf uns zukommen. Es ist möglich, so diese Abfragen in einem zentralen Daten-Modul platzieren, aber das ist nur Geographie, und erfordert Sorgfalt, so dass zwei separate Teile der Anwendung nicht versucht die gleiche Abfrage gleichzeitig zu verwenden.
Zurück in der geordneten Welt wohlformulierte Geschäftsobjekte offenlegen das Äquivalent eines Fremdschlüssels (in Form von unseren TObjectID) als öffentliche Eigenschaft ist ein Gräuel. Listing 1 zeigt, wie dies aussehen würde und ein kurzer Blick zeigt, dass wir unsere öffentliche Schnittstelle mit Details verfälscht haben, die wir lieber nicht aussetzen würde. Schließlich, wenn solche Eigenschaften öffentlich gemacht werden, dann kann jeder davon ausgehen, dass haben sie das Recht, sie zu benutzen.
Tun Sie es mit Objekten
Objektorientierung bietet uns eine weit natürlichere Art diese Beziehungen auszudrücken, statt durch implizite Fremdschlüsselfelder - wir tatsächlich das verknüpfte Objekt als Eigenschaft verfügbar machen können. Dies ermöglicht uns, solche Konstrukte wie Order.Customer und Order.StockItem zu verwenden, Zugriff auf die relevanten Objekte für unsere Bestellung. Hinweis: Dies ist eine natürliche und prägnante Weise auszudrücken, die Beziehungen und völlig versteckt die Implementierungsdetails. Wenn unsere sekundären Objekte selbst Beziehungen (z. B. das Unternehmen für einen Kunden) verfügbar machen ist dann finden die Versandadresse für eine Bestellung genauso einfach wie die Verwendung von Order.Customer.Company.Address, in einem extrem leistungsstark-Konstrukt. Es ist erwähnenswert, dass wenn wir später beschließen, das Verhältnis der Firma zu entfernen (oder tatsächlich die Art ändern, in der es implementiert ist), dann der Compiler erkennt jede Instanz in der gesamten Anwendung wo es falsch verwendet wird, und die Kompilierung schlägt fehl, bis alle Probleme behoben sind. Bereits hat Objektorientierung unterstützt, uns zu helfen, eine zuverlässigere Anwendung zu liefern: Wir machen Aussagen über die Tatsache, die alle relevante Änderungen vorgenommen wurden.
Vorausgesetzt, dass wir unsere verwandte Objekte als Eigenschaften verfügbar gemacht werden, wird wie das umgesetzt werden? Natürlich werden wir zu einem privaten 'Platzhalter' Feld müssen einen Verweis auf das verknüpfte Objekt speichern. Ein naive Ansatz wäre dieses verbundene Objekt in den Konstruktor erstellen und einfach haben die Eigenschaft, auf das private Feld zeigen. Dieser Ansatz hat zwei Hauptprobleme - eine unerwünschte und andere katastrophal. Unerwünschte geht, dass wir die Belastung für den Bau dieses verbundene Objekts, jedes Mal, wenn wir konstruieren die übergeordnete entstehen werden. Vorausgesetzt, dass wir die Eigenschaften des entsprechenden Objekts aus dem permanenten Speicher aufzufüllen, haben wir die Laufzeit-Performance unserer Anwendung mit den Aufwand für das Erstellen einer neuen Instanz und machen einen Datenbankzugriff beeinflusst. In der Regel lohnt es sich einige Sorgfalt den Konstruktor so einfach wie möglich zu halten. Erweitern diese Situation, man kann sehen, wenn Objekt A Ursachen der Instanziierung des Objekts B, Konstruktion von deren eigenen Konstruktor führt dazu, die Instanziierung von dem gleichen Objekt A dass dann wir werden die Welt der Endlosschleife eingeben und das erste, was, das ein Benutzer angezeigt wird, ist eine Out-of-Memory Fehlermeldung. Diese Situation ist nicht mehr als die sehr häufig 1-1-Entitätsbeziehung.
Die Lösung für dieses Problem ist eine Technik, die als Konstrukt on Demand oder faul Bau bekannt. Dies nutzt die Idee Bau des Objekts zu verzögern, bis kurz vor das erste Mal es erforderlich ist. Bei späteren Zugriffen wird einfach das bereits instanziierte Objekt zurückgegeben. Dies verzögert die teuren Operationen bis zum letzten möglichen Moment, während die übrigen transparent für alle Benutzer unserer Klasse. Listing 2 zeigt, wie dies umgesetzt werden kann. Vorerst, gehen wir davon aus, dass alle unsere TPDObjects eine Load-Methode, die füllt die Objekteigenschaften aus eine Art permanenter Speicher bieten, angesichts eine relevanten eindeutiges Objekt-ID.
Nutzung der Leistungsstärke von Objekten
Dies scheint unserer kaskadierende Bau lösen und ist eine Technik, die mit großem Erfolg mit jeder Eigenschaft (nicht nur Business-Objekte) kann, die möglicherweise teuer verwendet werden zu konstruieren ist. Aber lassen Sie uns darüber, was passieren wird, wenn wir diese Technik auf andere Business-Objekte anwenden. Was wird den Code für die Accessorfunktion von Order.StockItem aussehen oder in der Tat den allgemeinen Fall eines X.Y? Das Ergebnis sieht sehr ähnlich dem Listing 2, ersetzen neue Referenzen für die privaten Felder und entscheidend ist, den Typ der Klasse erstellt wird. Anstatt solche ähnlichen Code wiederholen (und Gefahr laufen, nicht Umsetzung solcher Accessorfunktionen identisch), gibt es eine Möglichkeit, in der wir die Kraft unserer Objekt-Hierarchie verwenden können, reduzieren diese Codierung? Es überrascht nicht, ist die Antwort einer emphatischen ja.
Was wir gerne tun würde ist irgendeine Dienstprogrammfunktion in unserer TPDObject-Basisklasse (Teil unseres Frameworks anwendungsunabhängig) bieten die erfüllt die gleiche Funktion, aber irgendwie parametriert werden können. Die wichtigsten Details, die wir benötigen, um als Parameter zu übergeben sind der Platzhalter für das Objekt erstellt wird, die ID, die geladen werden sollen und irgendwie die richtige Klasse zu konstruieren. Für die Erreichung dieser letzten Parameter verwenden wir ein Konstrukt namens einen Klassenverweis, der eine Variable ist, die einen bestimmten Typ als Teil einer Klassenhierarchie enthält. In Delphi wird dies mit der Schlüsselwort-Klasse definiert. Listing 3 zeigt die Änderungen auf unsere Rahmen-Einheit um diese Funktionalität bereitzustellen. Beachten Sie, dass die Objektinstanz tatsächlich in der Routine aktualisiert werden wird und dies ist daher eine der wenigen Gelegenheiten wo ein Objekt als Var-Parameter übergeben werden soll.
Ein anderes Element der Hinweis ist, dass der Konstruktor für TPDObject jetzt als virtuell definiert wurde. Ohne dies unsere generischen Routine wäre nicht in der Lage, einen bestimmte Klassenkonstruktor aufrufen und würde immer Klassen des Typs TPDObject konstruieren. Dies ist die gleiche Vorgehensweise wie für Komponenten in Delphi verwendet wird, und die Folge ist das gleiche: alle unsere Konstruktoren für unsere TPDObject nachkommen müssen jetzt verwenden Sie das Schlüsselwort zu überschreiben .
Wie werden unsere Accessor-Funktionen auf unserer Business-Objekte nun diese verfügbare Methode verwenden? Ihre Schnittstellen müssen, parameterlosen unverändert. Jedoch können wir den Aufruf in eine einzige Zeile Code wie in Listing 4 implementieren. Zwei Faktoren hervorzuheben: das Ergebnis des Aufrufs muss sein Typumwandlung zu 'tCustomer' wie es eine Art TPDObject gibt, obwohl die eigentliche Instanz den richtigen Typ sein wird. Zweitens muss das private FCustomer-Feld geändert werden, um TPDObject zu geben. Dies ist, weil Delphi beharrt, dass Var-Parameter genau den erwarteten Typ sind. In beiden Fällen sind diese sicherer Betrieb, da die Details privat sind und garantiert ist eine Klasse von den erwarteten Typ zurückgegeben werden, auch wenn die Vorgänger-Klasse keine Kenntnis davon hat. Wir sind jetzt in der Lage, solche Beziehungen in einer Codezeile implementieren, mithilfe einer zentralisierten anwendungsunabhängig Routine. Die Vorteile einer echten OO-Entwicklung beginnen, sich bekannt zu machen. Habend konstruiert diese Geschäftsobjekte in Verbindung, wir sorgen dafür, dass sie vernichtet werden. Ein einfacher Ansatz besteht darin, standard-aufrufen zu gratis im Destruktor zu platzieren: den Schutz um freien Willen zu gewährleisten, dass unerwünschte nichts passieren wird, wenn das Objekt nicht tatsächlich gebaut worden ist (frei auf ein NULL-Objekt ist eine zulässige Operation).
Letzte Artikel-problem
Zuvor spielte ich auf den Satz von Klassen, die nicht in eine 'echte' OO-Anwendung verwendet werden soll. Abbildung 1 aus Artikel des letzten Monats zeigt, dass die Elemente der Benutzeroberfläche nicht mit der Persistenz-Schicht, nur die Problemdomäne interagieren können. Datenbezogene Komponenten brechen diese Regel Änderungen direkt an die Datenbank-Verbindung sendet und daher (kontrovers) sollte nicht verwendet werden. Es gibt viele bessere, Alternativen und diesen Willen untersuchten in Zukunft Spalten.
(((Listing 1 - vermischen eine Klasse mit Eigenschaften, Beziehungen zu unterstützen)))
Typ
TOrder = Class (TMyAppPDObject)
Private
FCustomerID: TObjectID;
öffentliche
Eigenschaft CustomerID: TObjectID lesen FCustomerID;
... / / Andere Eigenschaften folgen...
Ende;
(((Ende Codebeispiel 1)))
(((Listing 2 - mit faul Bau für verknüpfte Objekte)))
Typ
TOrder = Class (TMyAppPDObject)
Private
FCustomerID: TObjectID;
FCustomer: 'TCustomer';
GetCustomer-Funktion: 'tCustomer';
öffentliche
Eigenschaft Kunde: 'tCustomer' lesen GetCustomer;
... / / Andere Eigenschaften folgen...
Ende;
Funktion TOrder.GetCustomer: 'tCustomer';
beginnen
Wenn FCustomer = NULL, dann beginnen
FCustomer: = TCustomer.Create;
FCustomer.Load (FCustomerID);
Ende;
Ergebnis: = FCustomer;
Ende;
(((Ende Codebeispiel 2)))
(((Listing 3 - generische faul Bau verbundener Objekte)))
Typ
TPDClass = Klasse von TPDObject;
TPDObject = Klasse
geschützt
GetObject-Funktion (const ClassType: TPDClass; Var PDObject: TPDObject; const-ID: TObjectID): TPDObject;
öffentliche
Konstruktor erstellen; virtuellen;
Verfahren Load (ID: TObjectID);
Ende;
Funktion TPDObject.GetObject (const ClassType: TPDClass; Var PDObject: TPDObject; const-ID: TObjectID): TPDObject;
beginnen
Wenn PDObject = NULL, dann beginnen
PDObject: = ClassType.Create;
Wenn ID <> NotAssigned dann PDObject.Load (ID);
Ende;
Ergebnis: = PDObject;
Ende;
(((Ende Codebeispiel 3)))
(((Listing 4 - unsere neue TOrder.Customer-Accessorfunktion)))
Funktion TOrder.GetCustomer: 'tCustomer';
beginnen
Ergebnis: = 'tCustomer' (GetObject ('tCustomer', FCustomer, FCustomerID));
Ende;
(((Ende Codebeispiel 4)))
Weiter in Serie
Einfaches Objekt-Beziehungen
Einfaches Objekt-Beziehungen : Mehreren tausend Tipps, um Ihr Leben einfacher machen.
Business-Objekte wie um sich selbst und ihren Beziehungen verfügbar zu machen. In diesem Artikel zeige ich Ihnen wie.
Einfaches Objekt-Beziehungen
Im letzten Artikel haben wir uns wie die klassische Lager, Bestellungen und der Kunden-Anforderung als drei separate Geschäftsobjekte jeder Aufdeckung ihres Staates durch klar definierte Eigenschaften modelliert werden könnte. Obwohl diese Objekte nun als verwendet werden konnte-ist (obwohl in sehr begrenztem Umfang - wir haben nicht noch definiert, wie ihre Informationen persistent machen!), ihnen fehlt jede Konzept von Beziehungen. Mit anderen Worten, wie können wir wissen die Kunden platziert eine Bestellung, bzw. welche StockItem?
Es ist einleuchtend, zu diesem Zeitpunkt innezuhalten und nachzudenken, wie dies traditionell in einer nicht-OO, datenorientierte Mode behandelt werden würde. Normalerweise würde ein Datenbankeintrag, darstellt die Reihenfolge zwei zusätzliche Feldern speichern einen Fremdschlüssel der Tabelle Kunden, und eine andere auf die StockItem-Tabelle verfügbar. Einer der Mängel dieses Ansatzes hat bereits bewiesen: alle Datenbankfelder ausgesetzt sind, im gleichen Maße; Es gibt kein Konzept für ein Feld als 'Privat' als die andere. Natürlich ist es möglich, dies zu einem gewissen Grad über einen Datenbank-View auszudrücken, aber bei den raw-Daten können nicht Ebene Felder namentlich in Bezug auf die Sichtbarkeit oder Rolle außer unterschieden werden und dem Weg-Wahnsinn liegt.
Nun betrachten Sie wir, wie wir Informationen über den Kunden zugreifen, die einen gegebenen Reihenfolge in diesem traditionellen Modell aufgegeben würde. Vorausgesetzt, dass wir die Informationen über die Reihenfolge, in eine Art von Dataset (vielleicht TQuery) haben, würden wir den Wert der das Fremdschlüsselfeld Kunden, erstellen Sie eine neue Abfrage auswählen aus der Customer-Tabelle basierend auf diesem Wert und untersuchen Sie dann die zurückgegebenen Daten. Hinweis: Dies ist eigentlich ziemlich viel Code zu schreiben, erfordert mindestens ein lokales Objekt (Kunden-Dataset) konstruiert werden, und solchen Code wuchert schnell, wenn wir auf die Lagerposition oder andere ähnliche Datenelemente zugreifen müssen. Eine Alternative zu diesem Ansatz besteht darin, alle Daten in einer einzigen Abfrage mit einem Multi-Tisch-Join auswählen. Dies überwindet die Menge an Code geschrieben werden, sondern stellt ein weiteres Problem - das harte Kodierung der Datenbeziehungen innerhalb der Abfragezeichenfolge. In etwas anderes als eine triviale Anwendung solcher Ausdrücke werden an vielen verschiedenen Orten im ganzen - wiederholt, und es ist erwähnenswert, dass der Compiler, nichts tun kann zu helfen, die Richtigkeit solcher Abfragen. Wenn Sie Datenbank-Grundlagen (vielleicht ändern, des Namens oder der Typ der das Fremdschlüsselfeld in einer Tabelle) ändern, ist es notwendig anwendungsweiten Suche und Techniken, um Vorkommnisse zu finden, die Aktualisierung möglicherweise ersetzen. In dieser Situation ist es durchaus möglich, dass einige selten genutzte Form werden durch das Netz fallen und behalten einen veraltet-Verweis auf ein Feld, das nicht mehr existiert. Dies ist ein Laufzeitfehler auf uns zukommen. Es ist möglich, so diese Abfragen in einem zentralen Daten-Modul platzieren, aber das ist nur Geographie, und erfordert Sorgfalt, so dass zwei separate Teile der Anwendung nicht versucht die gleiche Abfrage gleichzeitig zu verwenden.
Zurück in der geordneten Welt wohlformulierte Geschäftsobjekte offenlegen das Äquivalent eines Fremdschlüssels (in Form von unseren TObjectID) als öffentliche Eigenschaft ist ein Gräuel. Listing 1 zeigt, wie dies aussehen würde und ein kurzer Blick zeigt, dass wir unsere öffentliche Schnittstelle mit Details verfälscht haben, die wir lieber nicht aussetzen würde. Schließlich, wenn solche Eigenschaften öffentlich gemacht werden, dann kann jeder davon ausgehen, dass haben sie das Recht, sie zu benutzen.
Tun Sie es mit Objekten
Objektorientierung bietet uns eine weit natürlichere Art diese Beziehungen auszudrücken, statt durch implizite Fremdschlüsselfelder - wir tatsächlich das verknüpfte Objekt als Eigenschaft verfügbar machen können. Dies ermöglicht uns, solche Konstrukte wie Order.Customer und Order.StockItem zu verwenden, Zugriff auf die relevanten Objekte für unsere Bestellung. Hinweis: Dies ist eine natürliche und prägnante Weise auszudrücken, die Beziehungen und völlig versteckt die Implementierungsdetails. Wenn unsere sekundären Objekte selbst Beziehungen (z. B. das Unternehmen für einen Kunden) verfügbar machen ist dann finden die Versandadresse für eine Bestellung genauso einfach wie die Verwendung von Order.Customer.Company.Address, in einem extrem leistungsstark-Konstrukt. Es ist erwähnenswert, dass wenn wir später beschließen, das Verhältnis der Firma zu entfernen (oder tatsächlich die Art ändern, in der es implementiert ist), dann der Compiler erkennt jede Instanz in der gesamten Anwendung wo es falsch verwendet wird, und die Kompilierung schlägt fehl, bis alle Probleme behoben sind. Bereits hat Objektorientierung unterstützt, uns zu helfen, eine zuverlässigere Anwendung zu liefern: Wir machen Aussagen über die Tatsache, die alle relevante Änderungen vorgenommen wurden.
Vorausgesetzt, dass wir unsere verwandte Objekte als Eigenschaften verfügbar gemacht werden, wird wie das umgesetzt werden? Natürlich werden wir zu einem privaten 'Platzhalter' Feld müssen einen Verweis auf das verknüpfte Objekt speichern. Ein naive Ansatz wäre dieses verbundene Objekt in den Konstruktor erstellen und einfach haben die Eigenschaft, auf das private Feld zeigen. Dieser Ansatz hat zwei Hauptprobleme - eine unerwünschte und andere katastrophal. Unerwünschte geht, dass wir die Belastung für den Bau dieses verbundene Objekts, jedes Mal, wenn wir konstruieren die übergeordnete entstehen werden. Vorausgesetzt, dass wir die Eigenschaften des entsprechenden Objekts aus dem permanenten Speicher aufzufüllen, haben wir die Laufzeit-Performance unserer Anwendung mit den Aufwand für das Erstellen einer neuen Instanz und machen einen Datenbankzugriff beeinflusst. In der Regel lohnt es sich einige Sorgfalt den Konstruktor so einfach wie möglich zu halten. Erweitern diese Situation, man kann sehen, wenn Objekt A Ursachen der Instanziierung des Objekts B, Konstruktion von deren eigenen Konstruktor führt dazu, die Instanziierung von dem gleichen Objekt A dass dann wir werden die Welt der Endlosschleife eingeben und das erste, was, das ein Benutzer angezeigt wird, ist eine Out-of-Memory Fehlermeldung. Diese Situation ist nicht mehr als die sehr häufig 1-1-Entitätsbeziehung.
Die Lösung für dieses Problem ist eine Technik, die als Konstrukt on Demand oder faul Bau bekannt. Dies nutzt die Idee Bau des Objekts zu verzögern, bis kurz vor das erste Mal es erforderlich ist. Bei späteren Zugriffen wird einfach das bereits instanziierte Objekt zurückgegeben. Dies verzögert die teuren Operationen bis zum letzten möglichen Moment, während die übrigen transparent für alle Benutzer unserer Klasse. Listing 2 zeigt, wie dies umgesetzt werden kann. Vorerst, gehen wir davon aus, dass alle unsere TPDObjects eine Load-Methode, die füllt die Objekteigenschaften aus eine Art permanenter Speicher bieten, angesichts eine relevanten eindeutiges Objekt-ID.
Nutzung der Leistungsstärke von Objekten
Dies scheint unserer kaskadierende Bau lösen und ist eine Technik, die mit großem Erfolg mit jeder Eigenschaft (nicht nur Business-Objekte) kann, die möglicherweise teuer verwendet werden zu konstruieren ist. Aber lassen Sie uns darüber, was passieren wird, wenn wir diese Technik auf andere Business-Objekte anwenden. Was wird den Code für die Accessorfunktion von Order.StockItem aussehen oder in der Tat den allgemeinen Fall eines X.Y? Das Ergebnis sieht sehr ähnlich dem Listing 2, ersetzen neue Referenzen für die privaten Felder und entscheidend ist, den Typ der Klasse erstellt wird. Anstatt solche ähnlichen Code wiederholen (und Gefahr laufen, nicht Umsetzung solcher Accessorfunktionen identisch), gibt es eine Möglichkeit, in der wir die Kraft unserer Objekt-Hierarchie verwenden können, reduzieren diese Codierung? Es überrascht nicht, ist die Antwort einer emphatischen ja.
Was wir gerne tun würde ist irgendeine Dienstprogrammfunktion in unserer TPDObject-Basisklasse (Teil unseres Frameworks anwendungsunabhängig) bieten die erfüllt die gleiche Funktion, aber irgendwie parametriert werden können. Die wichtigsten Details, die wir benötigen, um als Parameter zu übergeben sind der Platzhalter für das Objekt erstellt wird, die ID, die geladen werden sollen und irgendwie die richtige Klasse zu konstruieren. Für die Erreichung dieser letzten Parameter verwenden wir ein Konstrukt namens einen Klassenverweis, der eine Variable ist, die einen bestimmten Typ als Teil einer Klassenhierarchie enthält. In Delphi wird dies mit der Schlüsselwort-Klasse definiert. Listing 3 zeigt die Änderungen auf unsere Rahmen-Einheit um diese Funktionalität bereitzustellen. Beachten Sie, dass die Objektinstanz tatsächlich in der Routine aktualisiert werden wird und dies ist daher eine der wenigen Gelegenheiten wo ein Objekt als Var-Parameter übergeben werden soll.
Ein anderes Element der Hinweis ist, dass der Konstruktor für TPDObject jetzt als virtuell definiert wurde. Ohne dies unsere generischen Routine wäre nicht in der Lage, einen bestimmte Klassenkonstruktor aufrufen und würde immer Klassen des Typs TPDObject konstruieren. Dies ist die gleiche Vorgehensweise wie für Komponenten in Delphi verwendet wird, und die Folge ist das gleiche: alle unsere Konstruktoren für unsere TPDObject nachkommen müssen jetzt verwenden Sie das Schlüsselwort zu überschreiben .
Wie werden unsere Accessor-Funktionen auf unserer Business-Objekte nun diese verfügbare Methode verwenden? Ihre Schnittstellen müssen, parameterlosen unverändert. Jedoch können wir den Aufruf in eine einzige Zeile Code wie in Listing 4 implementieren. Zwei Faktoren hervorzuheben: das Ergebnis des Aufrufs muss sein Typumwandlung zu 'tCustomer' wie es eine Art TPDObject gibt, obwohl die eigentliche Instanz den richtigen Typ sein wird. Zweitens muss das private FCustomer-Feld geändert werden, um TPDObject zu geben. Dies ist, weil Delphi beharrt, dass Var-Parameter genau den erwarteten Typ sind. In beiden Fällen sind diese sicherer Betrieb, da die Details privat sind und garantiert ist eine Klasse von den erwarteten Typ zurückgegeben werden, auch wenn die Vorgänger-Klasse keine Kenntnis davon hat. Wir sind jetzt in der Lage, solche Beziehungen in einer Codezeile implementieren, mithilfe einer zentralisierten anwendungsunabhängig Routine. Die Vorteile einer echten OO-Entwicklung beginnen, sich bekannt zu machen. Habend konstruiert diese Geschäftsobjekte in Verbindung, wir sorgen dafür, dass sie vernichtet werden. Ein einfacher Ansatz besteht darin, standard-aufrufen zu gratis im Destruktor zu platzieren: den Schutz um freien Willen zu gewährleisten, dass unerwünschte nichts passieren wird, wenn das Objekt nicht tatsächlich gebaut worden ist (frei auf ein NULL-Objekt ist eine zulässige Operation).
Letzte Artikel-problem
Zuvor spielte ich auf den Satz von Klassen, die nicht in eine 'echte' OO-Anwendung verwendet werden soll. Abbildung 1 aus Artikel des letzten Monats zeigt, dass die Elemente der Benutzeroberfläche nicht mit der Persistenz-Schicht, nur die Problemdomäne interagieren können. Datenbezogene Komponenten brechen diese Regel Änderungen direkt an die Datenbank-Verbindung sendet und daher (kontrovers) sollte nicht verwendet werden. Es gibt viele bessere, Alternativen und diesen Willen untersuchten in Zukunft Spalten.
(((Listing 1 - vermischen eine Klasse mit Eigenschaften, Beziehungen zu unterstützen)))
Typ
TOrder = Class (TMyAppPDObject)
Private
FCustomerID: TObjectID;
öffentliche
Eigenschaft CustomerID: TObjectID lesen FCustomerID;
... / / Andere Eigenschaften folgen...
Ende;
(((Ende Codebeispiel 1)))
(((Listing 2 - mit faul Bau für verknüpfte Objekte)))
Typ
TOrder = Class (TMyAppPDObject)
Private
FCustomerID: TObjectID;
FCustomer: 'TCustomer';
GetCustomer-Funktion: 'tCustomer';
öffentliche
Eigenschaft Kunde: 'tCustomer' lesen GetCustomer;
... / / Andere Eigenschaften folgen...
Ende;
Funktion TOrder.GetCustomer: 'tCustomer';
beginnen
Wenn FCustomer = NULL, dann beginnen
FCustomer: = TCustomer.Create;
FCustomer.Load (FCustomerID);
Ende;
Ergebnis: = FCustomer;
Ende;
(((Ende Codebeispiel 2)))
(((Listing 3 - generische faul Bau verbundener Objekte)))
Typ
TPDClass = Klasse von TPDObject;
TPDObject = Klasse
geschützt
GetObject-Funktion (const ClassType: TPDClass; Var PDObject: TPDObject; const-ID: TObjectID): TPDObject;
öffentliche
Konstruktor erstellen; virtuellen;
Verfahren Load (ID: TObjectID);
Ende;
Funktion TPDObject.GetObject (const ClassType: TPDClass; Var PDObject: TPDObject; const-ID: TObjectID): TPDObject;
beginnen
Wenn PDObject = NULL, dann beginnen
PDObject: = ClassType.Create;
Wenn ID <> NotAssigned dann PDObject.Load (ID);
Ende;
Ergebnis: = PDObject;
Ende;
(((Ende Codebeispiel 3)))
(((Listing 4 - unsere neue TOrder.Customer-Accessorfunktion)))
Funktion TOrder.GetCustomer: 'tCustomer';
beginnen
Ergebnis: = 'tCustomer' (GetObject ('tCustomer', FCustomer, FCustomerID));
Ende;
(((Ende Codebeispiel 4)))
Weiter in Serie
Einfaches Objekt-Beziehungen
By Wiezutun
Einfaches Objekt-Beziehungen : Mehreren tausend Tipps, um Ihr Leben einfacher machen.