Durchführung der Sätze von Objekten


In diesem Artikel weiter habe ich mein Blick auf die Umsetzung der Sätze von Objekten.
Prägnante benutzerdefinierten Konstruktoren
In meinem letzte Artikel habe ich die Breite Grundsätze hinter Umsetzung Sätze von Objekten mit einer Problemdomäne orientierte Klasse als Container für die Business-Objekte selbst zu handeln. Das verlassen einer erweiterten Daten-Management-Klasse, die Navigation über einen Datenbank-abhängige Cursor irgendeiner Art unterstützen könnte. Diesen Monat kommt zu dem Schluss dieser Untersuchung durch einige weitere Implementierungsdetails bereitstellen, und wir sehen, dass sobald das Anwendungsframework unabhängigen angegeben wurde, der eigentliche Code, der benötigt für ein echtes System sehr klein.
Wir haben bereits die vorgeschlagene Schnittstelle für unsere Klasse gesehen, die die Gruppe von Business Objects, TPDList verarbeitet. Dies hat klassische zunächst weiter und IsLast-Methoden, die delegieren abreagieren an ein Verwaltungsobjekt private Daten, die entsprechend den Anforderungen der betreffenden Liste aufgebaut ist. Dies ist der Code für unsere TPDList-Basiskonstruktor:
Konstruktor TPDList.Create (ListDMObject: TDMObject);
beginnen
geerbte erstellen; Standard-Konstruktor
DMObject: = ListDMobject; Private Referenz
Ende;
Dieser Code zeigt, dass der Konstruktor erwartet ein Daten-Management-Objekt als Parameter übergeben werden. Dies dürfte in den richtigen Typ zur Unterstützung der Liste Vorgänge für die betreffende Klasse erfolgen und wird von den anwendungsspezifischen Liste-Konstruktor gestellt. Sobald diese Daten Verwaltungsobjekts an unserer Liste übergeben wurde, es übernimmt die volle Verantwortung dafür und deshalb im Destruktor frei muss. Dies bricht eine übliche Faustregel wo eine Klasse sollte zerstört werden, im Umfang und Kontext, in dem es erstellt wurde, aber es erlaubt für einige besonders prägnante coding, die erleichtert die Belastung, wenn Sie diese Klassen in einer Anwendung zu implementieren.
Listing 1 zeigt die eigentliche Implementierung einer TCustomerList-Klasse, die eine Anzahl von Konstruktoren verfügt. Wie gesehen werden kann, dass jeder benutzerdefinierten Konstruktor ruft einfach den standard geerbten Konstruktor erstellen dynamisch Verwaltungsobjekts Daten erforderlich. Ein bestimmter Punkt ist, dass der Parameter an dem zweiten Konstruktor, der die Schnittstelle zwischen Logik und Persistenz Geschäftsklassen Datenbank-Neutral zu halten unverändert übergeben werden. Es ist neben der Eigenschaft, die das 'aktuelle' Problem Domain-Objekt aus der Liste, Typumwandlung zu einem geeigneten Typs zurückgibt, die Implementierung, die die Business-Logik für jeden neuen Typ der Liste benötigt, muss. Wie gesehen werden kann, ist dies eine sehr kleine Menge Code, da die meiste Arbeit geschieht in unserem anwendungsunabhängig Basisklassen.
Kapselnden Datenbankzugriff
Die unsere Business-Logik für die Behandlung dieser Lists also leicht ist deshalb, weil sie alle Arbeiten an ihrer jeweiligen Verwaltung Datenobjekte delegieren. Abhängig von der bestimmten Datenbank die Objektdaten beibehalten werden, kann die Menge an Arbeit erfordert hier enorm variieren. Glücklicherweise die überwiegende Mehrheit der Systeme in diesen Tagen speichern ihre Daten in einem RDBMS oder zumindest Zugang die Daten über eine Abfragesprache, in welche RS-Implementierung einfach ist.
Unsere Daten-Management-Klasse benötigen einen privaten Cursor irgendeiner Art auf die Datenbank. Ich gehe davon aus, dass der Cursor (in diesem Fall) hat die Fähigkeit, eine SQL-Abfrage ausführen und die Daten abrufen. Natürlich wird dieser Cursor ganz datenbankabhängige; Ich wähle in der Regel am schnellsten, am meisten bequem oder einfachste Option für eine bestimmte Datenbank bereitstellen. Dies könnte eine generische API wie ADO oder ODBC oder meistens beschäftigen ich einen spezifischen Ansatz wie beispielsweise eine Schnittstelle an einen Client API, vielleicht mit einem einfachen Wrapper (wie IBExpress für Interbase Zugriff). Einige können Frage, warum nicht die Datenbank komplett Schicht um eine datenbankunabhängige API wie z. B. ODBC Build. Es gibt nichts zu sagen, dass dies keine tragfähige Lösung, aber die Schnittstelle zu dem Datenbank-Layer zu halten, völlig neutral (und objektbasierte) hat den Vorteil, alle solche API verwendet werden, die gegebenenfalls zu ermöglichen. Die eigentliche Implementierung der Datenbank-Schicht ist natürlich frei, jede API zu verwenden, es dies auch generisch, wie ADO, ODBC oder die BDE wünscht. Es sollte betont werden, die Bereitstellung unserer eigenen Datenbank-Neutral-Schnittstelle für Objektpersistenz nicht das Rad neu zu erfinden ist; Unsere Schnittstelle ist ein sehr leichtgewichtiger Wrapper (oft als die Fassadenmuster implementiert) um ein funktioneller API, denen der Großteil der Arbeit übertragen wird. Der Schlüssel ist, dass unsere Wrapper die erforderliche Funktionen kapselt und erleichtert die Auswahl einer alternative Datenbank API Anforderungen ändern sollten oder diktieren muss.
Die FirstRecord-Methode für unsere Klasse (durch die erste Methode in der TPDList genannt) einfach bricht jede ausgeführte Abfrage innerhalb der Klasse und gibt die entsprechende SELECT-Abfrage. Die NextRecord wird auf eine geeignete Methode für den Datenbankcursor zugeordnet werden, ebenso wie die IsLast-Eigenschaft. Wie jeden Datensatz im Cursor zugegriffen wird, sollte die Daten-Management-Klasse instanziieren und füllen eine entsprechende Business-Objekt erwartet von der aufrufenden TPDList vorbereitet werden. Die Bevölkerung dieser Klasse aus die Datenbankfelder der Cursor sollte durch die Load-Methode mit der Bevölkerung eines einzelnen Objekts geteilt werden und wird am besten erreicht durch Aufrufen einer abstrakten Methode, vorbei an den Datenbankcursor und das Objekt aufgefüllt werden. Diese Methode muss überschrieben werden, durch unsere Anwendung bestimmte Daten Management-Objekte tatsächlich die bekannten Eigenschaften einer bestimmten Geschäftsobjekts aus benannten Felder im bereitgestellten Cursor aktualisieren.
Wir haben bereits erklärt, dass unsere Daten-Management-Klassen Konstruktoren haben werden, die denen in äquivalenten Liste Domäne Problem entsprechen. Vorausgesetzt, dass unsere Datenbank Abfragen unterstützt, alles, was diese Konstruktoren tun müssen, ist eine Abfragezeichenfolge definieren, die die benötigten Datensätze aus der Tabelle dynamisch Aufbau der Abfrage aus den übergebenen Parametern wählt. Für Abfragen, die sehr häufig ausgeführt werden, oder wo Leistung wichtig ist, ist es natürlich möglich für diesen Konstruktor aufrufen, eine benutzerdefinierte gespeicherte Prozedur in der Datenbank, übergibt dieser Parameter durch eine bequeme Form (z. B. Substitution Objekt ID's für referenzierte Objekte als Parameter übergeben). Die FirstRecord-Methode in unserer Klasse wird verantwortlich für die Initiierung der Ausführung der Abfrage oder eine gespeicherte Prozedur; Dies ist empfehlenswert, da sie den Konstruktor der Klasse leichtes hält. Listing 2 zeigt die entsprechenden Konstruktoren für die CustomerDM (Datenmanagement) Objekt.
Hierarchien der Verantwortung

Ich sollte endlich Kommentar der Klassenhierarchie auf die Datenseite Verwaltung beteiligten weiterleiten. Unsere Basis TDMObject datenbankunabhängige aufbewahrt werden, sondern stellen eine Schnittstelle, die die Domäne Problemklassen verwenden können. Dies wird erreicht durch die Bereitstellung einer Reihe von abstrakten Methoden in der Basisklasse. Tatsächliche Datenbankabhängigkeiten sind benutzerdefinierte Nachkommen des TDMObject (z. B. TSQLServerDMObject oder TOracleDMObject) eingeführt, die die abstrakten Methoden implementieren, bieten Ihnen die Dienstleistungen zur Unterstützung der Datenbankzugriff gegen ihre Zielplattform und möglicherweise bieten weitere abstrakte Methoden, die von den Nachkommen umgesetzt werden sollte.
Diese Datenbank-spezifische Nachkommen sind perfekt berechtigt, Abhängigkeiten von anderer Klassen vorstellen, die sie benötigen, um mit ihren gewählten Datenbank mit jeder geeigneten API zu kommunizieren. In der Regel liefern sie eine angemessene Menge an Funktionen für die Unterstützung von Themen wie Herstellen einer Verbindung mit der Engine, eine bestimmte Datenbank auswählen, und so weiter als benannte Benutzer einloggen. Wie sie solche Bedürfnisse zu erreichen ist völlig unter ihrer eigenen Kontrolle: nicht vergessen, dass unsere TDMObject-Basisschnittstelle ein Vertrag rein für die Dienste der TPDObject und TPDList vorgeschrieben ist, und keine Details wie ein Datenbankkontext diktieren. Dies bedeutet auch, dass unsere Datenbank-Objekten alle Eigenschaften der ausgewählten Datenbank oder API zur Maximierung der Einfachheit der Nutzung oder Leistung beim Ausruhen einfach in dem Wissen nutzen können, dass ein Wechsel zu einer anderen Datenbank ohne Großhandel Veränderungen an den Hauptteil des Anwendungscodes noch möglich ist. In der Tat, wie diese Klassen Anwendung unabhängig sind, ist es möglich, dass eine Datenbank-Assistent möglicherweise hohe Komplexität (um maximale Leistung aus der API zu extrahieren), und eine einfache Schnittstelle für anwendungsspezifische Benutzer dieser Klassen zu übernehmen.
Diese Hierarchie als Nebeneffekt ist, dass unsere Anwendung Daten-Management-Objekte stark werden, um die Funktionalität einer bestimmten Datenbank-Ebene gebunden werden und eine Änderung der Datenbank daher eine Re-Implementierung von der Daten-Management-Objekte erfordert. Diese Auswirkungen kann reduziert oder möglicherweise sogar ganz entfernt werden, wenn alle datenbankspezifische Klassen mit identischen Leistungen ausgelegt sind; die Erfahrung zeigt, dass während dieser Ansatz praktisch für ähnliche Datenbank-API ist, bietet eine vollständig datenbankunabhängig Klassenhierarchie beschränkt die Möglichkeiten einer bestimmten Plattform nutzen. Es ist natürlich durchaus möglich Sub Hierarchien mit identische Schnittstellen, die Einführung gemeinsamer wird ein Satz von Datenbank-Objekten, die alle SQL als ihre wichtigste Mittel zur Kommunikation verwenden. Dies eignet sich für Hierarchien wie folgt, wobei die ersten drei Klassen liegen im Rahmen (und auch den Großteil des Codes), und die letzten beiden Klassen anwendungsspezifische sind:
TDMObject → TSQL_DMObject → TOracleDMObject → TMyAppDMObject → TCustomerDM
Letzte Artikel die Frage
Ich fragte, wie wir unsere neue Liste Klassen zur Darstellung von Objektbeziehungen wie 1: n-nutzen können. Ein klassisches Beispiel für eine solche Beziehung wäre Customer.Orders, die den Satz, der jemals von einem Kunden aufgegebenen Bestellungen. Wie bei unseren anderen 1-1 und n: 1 Beziehungen, ist das Verfügbarmachen von ihnen als Eigenschaft für die verknüpfte Klasse eine angenehme und natürliche Weise tun. Ist die erste Frage, wie sie umgesetzt werden können? Die Antwort darauf ist sehr einfach; Wir verwenden die Standardausführung faul-Techniken auf unsere Eigenschaft Accessor-Funktion nur die Liste zum ersten Mal erstellen, die, das es erforderlich ist. Die tatsächliche Liste konstruiert werden, wird die entsprechende Liste basierend auf die Beziehung, die wir zum Ausdruck gebracht werden, in diesem Fall würden wir die Liste der Bestellungen für einen bekannten Kunden aufbauen wollen. Listing 3 zeigt eine vollständige Implementierung für diese Beziehung. Das aussagekräftigste Merkmal ist die Verwendung von 'Selbst', eine Liste der Aufträge für eine bestimmte Instanz der Kunden zu konstruieren.
Der zweite Teil der Frage war: können wir behandeln solche Operationen generisch wie wir mit den einfacheren Verhältnissen (erinnern wir eine generische GetObject-Methode in unserer TPDObject-Basisklasse implementiert)? Auf den ersten Blick sind wir möglicherweise eine generische Methode GetList implementiert, aber bei näherer Betrachtung ist dies nicht der Fall. Der Grund für diese Unfähigkeit, Listen generisch verarbeitet ist, dass wir einen bestimmten Konstruktor mit bestimmten Parametern für die erforderlichen Liste aufrufen wollen. Dazu müsste eine Art einen Verweis auf einen Konstruktor, und es gibt keine präzise Möglichkeit auszudrücken, dies während der Parameterbehandlung einfach zu halten. So während wir einzelne Objektbeziehungen behandeln können wir nicht allgemein für Set Objektbeziehungen ähnlich und sie jeweils behandelt werden müssen explizit wie in Listing 1 dargestellt. Wie ersichtlich, die Menge an Code beteiligt ist minimal, und dies ist daher nicht zu erdrückend eine Aufgabe.
(((Listing 1 - Custom Konstruktoren für TCustomerList)))
Konstruktor TCustomerList.CreateAll;
beginnen
geerbte erstellen (TCustomerDM.CreateAll);
Ende;
Konstruktor TCustomerList.CreateByName (const Name: String);
beginnen
geerbte erstellen (TCustomerDM.CreateByName (Name));
Ende;
Konstruktor TCustomerList.CreateByStockOrder (Item: TStockItem);
beginnen
geerbte erstellen (TCustomerDM.CreateByStockOrder (Item));
Ende;
(((Ende Codebeispiel 1)))
(((Listing 2 - Matching Konstruktoren für das Kundendatenmanagement Objekt)))
Konstruktor TCustomerDM.CreateAll;
beginnen
geerbte erstellen;
Abfrage: = 'wählen Sie * aus Customer ORDER BY Name';
Ende;
Konstruktor TCustomerDM.CreateByName (const Name: String);
beginnen
geerbte erstellen;
Abfrage: = 'wählen Sie * von Kunden wo Namen wie'' + Name + ' % ';
Ende;
Konstruktor TCustomerDM.CreateByStockOrder (Item: TStockItem);
beginnen
geerbte erstellen;
Abfrage: = 'wählen Sie * von Kunden wo ItemID =' + IDToStr (Item.ID);
Ende;
(((Ende Codebeispiel 2)))
(((Listing 3 - Umsetzung 1: n-Beziehungen)))
Typ
'TCustomer' = Class (TPDObject)
Private
FOrders: TOrderList;
GetOrders-Funktion: TOrderList;
öffentliche
Destruktor Destroy; außer Kraft setzen;
Eigenschaft-Bestellungen: TOrderList lesen GetOrders;
Ende;
Destruktor TCustomer.Destroy;
beginnen
FOrders.Free;
erbte;
Ende;
Funktion TCustomer.GetOrders: TOrderList;
beginnen
Wenn FOrders = NULL dann FOrders: = TOrderList.CreateByCustomer (Self);
Ergebnis: = FOrders;
Ende;
(((Ende Codebeispiel 3)))









Durchführung der Sätze von Objekten


Durchführung der Sätze von Objekten : Mehreren tausend Tipps, um Ihr Leben einfacher machen.


In diesem Artikel weiter habe ich mein Blick auf die Umsetzung der Sätze von Objekten.
Prägnante benutzerdefinierten Konstruktoren
In meinem letzte Artikel habe ich die Breite Grundsätze hinter Umsetzung Sätze von Objekten mit einer Problemdomäne orientierte Klasse als Container für die Business-Objekte selbst zu handeln. Das verlassen einer erweiterten Daten-Management-Klasse, die Navigation über einen Datenbank-abhängige Cursor irgendeiner Art unterstützen könnte. Diesen Monat kommt zu dem Schluss dieser Untersuchung durch einige weitere Implementierungsdetails bereitstellen, und wir sehen, dass sobald das Anwendungsframework unabhängigen angegeben wurde, der eigentliche Code, der benötigt für ein echtes System sehr klein.
Wir haben bereits die vorgeschlagene Schnittstelle für unsere Klasse gesehen, die die Gruppe von Business Objects, TPDList verarbeitet. Dies hat klassische zunächst weiter und IsLast-Methoden, die delegieren abreagieren an ein Verwaltungsobjekt private Daten, die entsprechend den Anforderungen der betreffenden Liste aufgebaut ist. Dies ist der Code für unsere TPDList-Basiskonstruktor:
Konstruktor TPDList.Create (ListDMObject: TDMObject);
beginnen
geerbte erstellen; Standard-Konstruktor
DMObject: = ListDMobject; Private Referenz
Ende;
Dieser Code zeigt, dass der Konstruktor erwartet ein Daten-Management-Objekt als Parameter übergeben werden. Dies dürfte in den richtigen Typ zur Unterstützung der Liste Vorgänge für die betreffende Klasse erfolgen und wird von den anwendungsspezifischen Liste-Konstruktor gestellt. Sobald diese Daten Verwaltungsobjekts an unserer Liste übergeben wurde, es übernimmt die volle Verantwortung dafür und deshalb im Destruktor frei muss. Dies bricht eine übliche Faustregel wo eine Klasse sollte zerstört werden, im Umfang und Kontext, in dem es erstellt wurde, aber es erlaubt für einige besonders prägnante coding, die erleichtert die Belastung, wenn Sie diese Klassen in einer Anwendung zu implementieren.
Listing 1 zeigt die eigentliche Implementierung einer TCustomerList-Klasse, die eine Anzahl von Konstruktoren verfügt. Wie gesehen werden kann, dass jeder benutzerdefinierten Konstruktor ruft einfach den standard geerbten Konstruktor erstellen dynamisch Verwaltungsobjekts Daten erforderlich. Ein bestimmter Punkt ist, dass der Parameter an dem zweiten Konstruktor, der die Schnittstelle zwischen Logik und Persistenz Geschäftsklassen Datenbank-Neutral zu halten unverändert übergeben werden. Es ist neben der Eigenschaft, die das 'aktuelle' Problem Domain-Objekt aus der Liste, Typumwandlung zu einem geeigneten Typs zurückgibt, die Implementierung, die die Business-Logik für jeden neuen Typ der Liste benötigt, muss. Wie gesehen werden kann, ist dies eine sehr kleine Menge Code, da die meiste Arbeit geschieht in unserem anwendungsunabhängig Basisklassen.
Kapselnden Datenbankzugriff
Die unsere Business-Logik für die Behandlung dieser Lists also leicht ist deshalb, weil sie alle Arbeiten an ihrer jeweiligen Verwaltung Datenobjekte delegieren. Abhängig von der bestimmten Datenbank die Objektdaten beibehalten werden, kann die Menge an Arbeit erfordert hier enorm variieren. Glücklicherweise die überwiegende Mehrheit der Systeme in diesen Tagen speichern ihre Daten in einem RDBMS oder zumindest Zugang die Daten über eine Abfragesprache, in welche RS-Implementierung einfach ist.
Unsere Daten-Management-Klasse benötigen einen privaten Cursor irgendeiner Art auf die Datenbank. Ich gehe davon aus, dass der Cursor (in diesem Fall) hat die Fähigkeit, eine SQL-Abfrage ausführen und die Daten abrufen. Natürlich wird dieser Cursor ganz datenbankabhängige; Ich wähle in der Regel am schnellsten, am meisten bequem oder einfachste Option für eine bestimmte Datenbank bereitstellen. Dies könnte eine generische API wie ADO oder ODBC oder meistens beschäftigen ich einen spezifischen Ansatz wie beispielsweise eine Schnittstelle an einen Client API, vielleicht mit einem einfachen Wrapper (wie IBExpress für Interbase Zugriff). Einige können Frage, warum nicht die Datenbank komplett Schicht um eine datenbankunabhängige API wie z. B. ODBC Build. Es gibt nichts zu sagen, dass dies keine tragfähige Lösung, aber die Schnittstelle zu dem Datenbank-Layer zu halten, völlig neutral (und objektbasierte) hat den Vorteil, alle solche API verwendet werden, die gegebenenfalls zu ermöglichen. Die eigentliche Implementierung der Datenbank-Schicht ist natürlich frei, jede API zu verwenden, es dies auch generisch, wie ADO, ODBC oder die BDE wünscht. Es sollte betont werden, die Bereitstellung unserer eigenen Datenbank-Neutral-Schnittstelle für Objektpersistenz nicht das Rad neu zu erfinden ist; Unsere Schnittstelle ist ein sehr leichtgewichtiger Wrapper (oft als die Fassadenmuster implementiert) um ein funktioneller API, denen der Großteil der Arbeit übertragen wird. Der Schlüssel ist, dass unsere Wrapper die erforderliche Funktionen kapselt und erleichtert die Auswahl einer alternative Datenbank API Anforderungen ändern sollten oder diktieren muss.
Die FirstRecord-Methode für unsere Klasse (durch die erste Methode in der TPDList genannt) einfach bricht jede ausgeführte Abfrage innerhalb der Klasse und gibt die entsprechende SELECT-Abfrage. Die NextRecord wird auf eine geeignete Methode für den Datenbankcursor zugeordnet werden, ebenso wie die IsLast-Eigenschaft. Wie jeden Datensatz im Cursor zugegriffen wird, sollte die Daten-Management-Klasse instanziieren und füllen eine entsprechende Business-Objekt erwartet von der aufrufenden TPDList vorbereitet werden. Die Bevölkerung dieser Klasse aus die Datenbankfelder der Cursor sollte durch die Load-Methode mit der Bevölkerung eines einzelnen Objekts geteilt werden und wird am besten erreicht durch Aufrufen einer abstrakten Methode, vorbei an den Datenbankcursor und das Objekt aufgefüllt werden. Diese Methode muss überschrieben werden, durch unsere Anwendung bestimmte Daten Management-Objekte tatsächlich die bekannten Eigenschaften einer bestimmten Geschäftsobjekts aus benannten Felder im bereitgestellten Cursor aktualisieren.
Wir haben bereits erklärt, dass unsere Daten-Management-Klassen Konstruktoren haben werden, die denen in äquivalenten Liste Domäne Problem entsprechen. Vorausgesetzt, dass unsere Datenbank Abfragen unterstützt, alles, was diese Konstruktoren tun müssen, ist eine Abfragezeichenfolge definieren, die die benötigten Datensätze aus der Tabelle dynamisch Aufbau der Abfrage aus den übergebenen Parametern wählt. Für Abfragen, die sehr häufig ausgeführt werden, oder wo Leistung wichtig ist, ist es natürlich möglich für diesen Konstruktor aufrufen, eine benutzerdefinierte gespeicherte Prozedur in der Datenbank, übergibt dieser Parameter durch eine bequeme Form (z. B. Substitution Objekt ID's für referenzierte Objekte als Parameter übergeben). Die FirstRecord-Methode in unserer Klasse wird verantwortlich für die Initiierung der Ausführung der Abfrage oder eine gespeicherte Prozedur; Dies ist empfehlenswert, da sie den Konstruktor der Klasse leichtes hält. Listing 2 zeigt die entsprechenden Konstruktoren für die CustomerDM (Datenmanagement) Objekt.
Hierarchien der Verantwortung

Ich sollte endlich Kommentar der Klassenhierarchie auf die Datenseite Verwaltung beteiligten weiterleiten. Unsere Basis TDMObject datenbankunabhängige aufbewahrt werden, sondern stellen eine Schnittstelle, die die Domäne Problemklassen verwenden können. Dies wird erreicht durch die Bereitstellung einer Reihe von abstrakten Methoden in der Basisklasse. Tatsächliche Datenbankabhängigkeiten sind benutzerdefinierte Nachkommen des TDMObject (z. B. TSQLServerDMObject oder TOracleDMObject) eingeführt, die die abstrakten Methoden implementieren, bieten Ihnen die Dienstleistungen zur Unterstützung der Datenbankzugriff gegen ihre Zielplattform und möglicherweise bieten weitere abstrakte Methoden, die von den Nachkommen umgesetzt werden sollte.
Diese Datenbank-spezifische Nachkommen sind perfekt berechtigt, Abhängigkeiten von anderer Klassen vorstellen, die sie benötigen, um mit ihren gewählten Datenbank mit jeder geeigneten API zu kommunizieren. In der Regel liefern sie eine angemessene Menge an Funktionen für die Unterstützung von Themen wie Herstellen einer Verbindung mit der Engine, eine bestimmte Datenbank auswählen, und so weiter als benannte Benutzer einloggen. Wie sie solche Bedürfnisse zu erreichen ist völlig unter ihrer eigenen Kontrolle: nicht vergessen, dass unsere TDMObject-Basisschnittstelle ein Vertrag rein für die Dienste der TPDObject und TPDList vorgeschrieben ist, und keine Details wie ein Datenbankkontext diktieren. Dies bedeutet auch, dass unsere Datenbank-Objekten alle Eigenschaften der ausgewählten Datenbank oder API zur Maximierung der Einfachheit der Nutzung oder Leistung beim Ausruhen einfach in dem Wissen nutzen können, dass ein Wechsel zu einer anderen Datenbank ohne Großhandel Veränderungen an den Hauptteil des Anwendungscodes noch möglich ist. In der Tat, wie diese Klassen Anwendung unabhängig sind, ist es möglich, dass eine Datenbank-Assistent möglicherweise hohe Komplexität (um maximale Leistung aus der API zu extrahieren), und eine einfache Schnittstelle für anwendungsspezifische Benutzer dieser Klassen zu übernehmen.
Diese Hierarchie als Nebeneffekt ist, dass unsere Anwendung Daten-Management-Objekte stark werden, um die Funktionalität einer bestimmten Datenbank-Ebene gebunden werden und eine Änderung der Datenbank daher eine Re-Implementierung von der Daten-Management-Objekte erfordert. Diese Auswirkungen kann reduziert oder möglicherweise sogar ganz entfernt werden, wenn alle datenbankspezifische Klassen mit identischen Leistungen ausgelegt sind; die Erfahrung zeigt, dass während dieser Ansatz praktisch für ähnliche Datenbank-API ist, bietet eine vollständig datenbankunabhängig Klassenhierarchie beschränkt die Möglichkeiten einer bestimmten Plattform nutzen. Es ist natürlich durchaus möglich Sub Hierarchien mit identische Schnittstellen, die Einführung gemeinsamer wird ein Satz von Datenbank-Objekten, die alle SQL als ihre wichtigste Mittel zur Kommunikation verwenden. Dies eignet sich für Hierarchien wie folgt, wobei die ersten drei Klassen liegen im Rahmen (und auch den Großteil des Codes), und die letzten beiden Klassen anwendungsspezifische sind:
TDMObject → TSQL_DMObject → TOracleDMObject → TMyAppDMObject → TCustomerDM
Letzte Artikel die Frage
Ich fragte, wie wir unsere neue Liste Klassen zur Darstellung von Objektbeziehungen wie 1: n-nutzen können. Ein klassisches Beispiel für eine solche Beziehung wäre Customer.Orders, die den Satz, der jemals von einem Kunden aufgegebenen Bestellungen. Wie bei unseren anderen 1-1 und n: 1 Beziehungen, ist das Verfügbarmachen von ihnen als Eigenschaft für die verknüpfte Klasse eine angenehme und natürliche Weise tun. Ist die erste Frage, wie sie umgesetzt werden können? Die Antwort darauf ist sehr einfach; Wir verwenden die Standardausführung faul-Techniken auf unsere Eigenschaft Accessor-Funktion nur die Liste zum ersten Mal erstellen, die, das es erforderlich ist. Die tatsächliche Liste konstruiert werden, wird die entsprechende Liste basierend auf die Beziehung, die wir zum Ausdruck gebracht werden, in diesem Fall würden wir die Liste der Bestellungen für einen bekannten Kunden aufbauen wollen. Listing 3 zeigt eine vollständige Implementierung für diese Beziehung. Das aussagekräftigste Merkmal ist die Verwendung von 'Selbst', eine Liste der Aufträge für eine bestimmte Instanz der Kunden zu konstruieren.
Der zweite Teil der Frage war: können wir behandeln solche Operationen generisch wie wir mit den einfacheren Verhältnissen (erinnern wir eine generische GetObject-Methode in unserer TPDObject-Basisklasse implementiert)? Auf den ersten Blick sind wir möglicherweise eine generische Methode GetList implementiert, aber bei näherer Betrachtung ist dies nicht der Fall. Der Grund für diese Unfähigkeit, Listen generisch verarbeitet ist, dass wir einen bestimmten Konstruktor mit bestimmten Parametern für die erforderlichen Liste aufrufen wollen. Dazu müsste eine Art einen Verweis auf einen Konstruktor, und es gibt keine präzise Möglichkeit auszudrücken, dies während der Parameterbehandlung einfach zu halten. So während wir einzelne Objektbeziehungen behandeln können wir nicht allgemein für Set Objektbeziehungen ähnlich und sie jeweils behandelt werden müssen explizit wie in Listing 1 dargestellt. Wie ersichtlich, die Menge an Code beteiligt ist minimal, und dies ist daher nicht zu erdrückend eine Aufgabe.
(((Listing 1 - Custom Konstruktoren für TCustomerList)))
Konstruktor TCustomerList.CreateAll;
beginnen
geerbte erstellen (TCustomerDM.CreateAll);
Ende;
Konstruktor TCustomerList.CreateByName (const Name: String);
beginnen
geerbte erstellen (TCustomerDM.CreateByName (Name));
Ende;
Konstruktor TCustomerList.CreateByStockOrder (Item: TStockItem);
beginnen
geerbte erstellen (TCustomerDM.CreateByStockOrder (Item));
Ende;
(((Ende Codebeispiel 1)))
(((Listing 2 - Matching Konstruktoren für das Kundendatenmanagement Objekt)))
Konstruktor TCustomerDM.CreateAll;
beginnen
geerbte erstellen;
Abfrage: = 'wählen Sie * aus Customer ORDER BY Name';
Ende;
Konstruktor TCustomerDM.CreateByName (const Name: String);
beginnen
geerbte erstellen;
Abfrage: = 'wählen Sie * von Kunden wo Namen wie'' + Name + ' % ';
Ende;
Konstruktor TCustomerDM.CreateByStockOrder (Item: TStockItem);
beginnen
geerbte erstellen;
Abfrage: = 'wählen Sie * von Kunden wo ItemID =' + IDToStr (Item.ID);
Ende;
(((Ende Codebeispiel 2)))
(((Listing 3 - Umsetzung 1: n-Beziehungen)))
Typ
'TCustomer' = Class (TPDObject)
Private
FOrders: TOrderList;
GetOrders-Funktion: TOrderList;
öffentliche
Destruktor Destroy; außer Kraft setzen;
Eigenschaft-Bestellungen: TOrderList lesen GetOrders;
Ende;
Destruktor TCustomer.Destroy;
beginnen
FOrders.Free;
erbte;
Ende;
Funktion TCustomer.GetOrders: TOrderList;
beginnen
Wenn FOrders = NULL dann FOrders: = TOrderList.CreateByCustomer (Self);
Ergebnis: = FOrders;
Ende;
(((Ende Codebeispiel 3)))


Durchführung der Sätze von Objekten

Durchführung der Sätze von Objekten : Mehreren tausend Tipps, um Ihr Leben einfacher machen.
Durchführung der Sätze von Objekten
Wiezutun
Freunden empfehlen
  • gplus
  • pinterest

Kommentar

Einen Kommentar hinterlassen

Wertung