Re: OOP: Erzeugen von Objekten & Co.
21. Okt 2009, 19:54
Oder grob anders formuliert: Mit der Ableitung von TXYListe von TStringList kann TXYListe alles was TStringList kann und noch ein wenig mehr. Somit kannst du einer TStringList Variablen auch deren Nachfahren als Instanz zuweisen, da alle Nachfahren mindestens das können was auch TStringList kann. Alle Abkömmlinge bilden neue Eigenschaften und Methoden aus und sind damit höher spezialisiert.
Im Gegenzug kannst du aber einer TXYListe Variablen keine Instanz von TStringList zuweisen, da TStringList nicht alles kann, was TXYListe kann.
Das ganze soll aber nicht das Lesen erschweren, dazu dient dies nicht. Aber es ist nicht üblich für Objektdeklarationen immer die höchsten Integrationstiefe zu nutzen. Sprich: es ist unüblich die höchste Spezialisierung für die Variable zu deklarieren. Wenn man dies macht, schränkt man sich bei der Nutzung selbst recht stark ein auf den Typ und dessen Nachfahren. Es ist sogar schon unüblich TStringList zu nutzen in der Deklaration von Variablen sondern eher TStrings. Diese sind der Vorfahre von TStringList.
Beispiel:
Wenn du eine Methode hast welche mit einer TStringList arbeitet, d.h. sie geht z.B. die Liste durch und holt sich immer die einzelnen Strings heraus und verarbeitet diese. Wenn nun diese Methode als Parameter diese TStringList entgegen nimmt, dann kannst du dies mit TStringList deklarieren. Damit legst du dich schon auf TStringList und deren Nachfahren fest. Diese Methode ist dann z.B. nicht anwendbar auf z.B. TListBox.Items. Diese stellen eine andere Ableitung von TStrings dar. Im Endeffekt gibt es aber keinen Grund warum deine Methode sich einschränkt auf TStringList, da sie nichts epezielles nutzt. Würdest du den Parameter aber auf den Vorfahren TStrings abändern, dann würde deine Methode immernoch den gleichen Code haben und genauso funktionieren, nur das du diesmal als Instanz eine TXYList, eine TListBox.Items, TComboBox.Items, TMemo.Lines und auch TStringList übergeben kannst (und noch viele andere) und mit diesen allen arbeitet sie zusammen. Wärst du bei dem höher spezialisierten Typ TStringList geblieben, müsstest du für jeden aufgezählten Kandidaten eine eigene Methode implementieren - dabei wäre der Inhalt immer der gleiche, nur der Parametertyp in der Signatur würde sich beständig ändern.
Das ist auch der Grund für TStrings: Sie bilden eine Menge an Grundfunktionalität ab, was alle gleich haben: eine Liste von Strings zu verwalten. Dabei gibt es noch die Besonderheit: TStrings ist eine abstrakte Basisklasse. Dies bedeutet: sie definiert die Properties und Methoden und alles was man braucht um mit einer Liste von Strings zu arbeiten, tut aber an keiner Stelle irgendwas mit Strings machen. Sie definiert diese Grundfunktionalität und die Ableitungen setzen diese dann um. TStringList oder auch TMemoStrings wiederrum kümmern sich um die Speicheralloziierung (bzw. das Setzen und Abfragen der visuellen Komponenten beim Zugriff auf .Lines). Da TStrings nur ein leeres Gerüst bietet, bekommst du Probleme wenn du eine Instanz von TStrings anlegst und damit arbeiten willst: du bekommst einen abstrakten Fehler, da TStrings keine Strings halten kann. Dies implementieren erst die Ableitungen, aber die ganzen Ableitungen haben alle eins gemeinsam: sie erben alle die Grundfunktionalität von TStrings. Und damit kann man sie allgemein benutzen, ansprechen, etc - wenn man sich auf den Typ TStrings konzentriert. Eine Variable kann immer höher, abgeleitete Klassen als Instanzen aufnehmen.
Anhang:
Die Instanzen sind erst zur Laufzeit vorhanden und in den Variablen abgelegt. Ob in der Variablen nun eine TStringList oder eine TXYListe enthalten ist, kann dir der Compiler zur Designzeit nicht beantworten. D.h. du kannst z.B. nicht eine von TXYListe neu eingeführte Methode aufrufen, wenn die Variable vom Typ TStringList ist. Aber du kannst abfragen ob eine höhere Spezialisierung vorhanden ist, mit dem IS Operator. Dieser liefert bei der Abfrage true, wenn die angefragte Klasse oder deren Ableitung als Instanz vorliegen.
|