Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Algorithmen, Datenstrukturen und Klassendesign (https://www.delphipraxis.net/78-algorithmen-datenstrukturen-und-klassendesign/)
-   -   Delphi TObjectList<> - Frage (https://www.delphipraxis.net/192407-tobjectlist-frage.html)

Benmik 15. Apr 2017 17:29

TObjectList<> - Frage
 
Ich habe eine TObjectList<TTyp1> mit einer Reihe von Prozeduren und Funktionen.
Ich würde diese Liste gern für einen TTyp2 verwenden, ohne den ganzen Code duplizieren zu müssen.
Ich würde darauf achten, dass TTyp2 alle Elemente von TTyp1 enthält, auf die sich die Prozeduren und Funktionen der Objektliste (z.B. Sortieren und Suchen) beziehen.

Geht sowas? Ich fürchte mal stark, mit Interfaces, insbesondere nach Lektüre dieses Beitrages. Zum einen benötige ich aber OwnsObjects und zum anderen gelingt es mir nicht, eine Liste zu bauen, der ich dann ein Interface zuordnen könnte, das wiederum verschiedene Objektklassen aufnehmen könnte. Oder ist der Ansatz verkehrt oder geht es anders?

Zacherl 15. Apr 2017 17:46

AW: TObjectList<> - Frage
 
Bin nicht sicher, ob ich dein Anliegen richtig verstanden habe, aber das klingt für mich, als könntest du dafür eine generische Klasse erstellen. Den generischen Typ beschränkst du auf ein eigenes Interface, welches alle erforderlichen Operationen unterstüzt. Typ1 und Typ2 müssen dann nur noch das Interface implementieren.

Alternativ ohne Interfaces und dafür mit gemeinsamer Basisklasse.

Benmik 15. Apr 2017 18:22

AW: TObjectList<> - Frage
 
Mensch, Zacherl, ein paar Worte und schon wird es lichter im Hirnkasten!
Mein Fehler war, dass ich versucht hatte für die Objektliste ein Interface zu implementieren, während es ja genügt, dies für die Objekte zu tun.

Jetzt bekomme ich allerdings das im Beitrag auf SO angesprochene Problem, die Implementierung der Objektliste geht nur mit Klassen, nicht mit Interfaces. Ich könnte eine TList implementieren und das OwnsObjekt als zusätzliches Feld mit aufnehmen, müsste dann die Freigabe selbst übernehmen. Ginge wohl auch noch.

Alternativ Basisklasse - eine Oberklasse erstellen und davon die benötigten Klassen ableiten? Hast du dafür ein kurzes Beispiel?

Zacherl 15. Apr 2017 18:49

AW: TObjectList<> - Frage
 
Ganz normale Vererbung halt:
Delphi-Quellcode:
type
  TBaseClass = class(TObject)
  public
    procedure CommonTest;
  end;

  TClass1 = class(TBaseClass)
  public
    procedure OnlyForClass1;
  end;

  TClass2 = class(TBaseClass)
  public
    procedure OnlyForClass2;
  end;
Und die verwaltende Klasse dann entsprechend:
Delphi-Quellcode:
type
  TManagerClass<T: TBaseClass> = class(TObject)
  public
    FList: TObjectList<T>;
  end;
Innerhalb des Codes solltest du dann dank des Constraints ohne Probleme auf alle Eigenschaften von TBaseClass zugreifen könne.

Benmik 15. Apr 2017 19:53

AW: TObjectList<> - Frage
 
Tja, hab noch nicht soviel vererbt... :stupid:

Ist ja völlig einfach. Kleine Frage vor allem nach der Lektüre dieses Beitrags:
Was passiert eigentlich wenn ich Felder in der abgeleiteten Klasse wiederhole?
Delphi-Quellcode:
type
  TBasis = class(TObject)
    Var1 : integer;
    Var2 : string;
  end;

type
  TErbe = class(TBasis)
    Var1 : integer;
    Var2 : string;
  end;

type
TListe = class(TObjectList<TBasis>)
public
  procedure SortiereVar1(Wert:integer)
end;
Nach meinen Versuchen hat das keine Auswirkungen; wenn ich nach Var1 sortiere, funktioniert das. Kann man sowas straflos tun?

Zacherl 15. Apr 2017 20:57

AW: TObjectList<> - Frage
 
Zitat:

Zitat von Benmik (Beitrag 1367819)
Was passiert eigentlich wenn ich Felder in der abgeleiteten Klasse wiederhole?

Die Felder werden verdeckt. Wenn du also z.b. eine Instanz von
Delphi-Quellcode:
TErbe
erstellst und dann Var1 den Wert 42 zuweist, ist
Delphi-Quellcode:
TBasis.Var1
immer noch 0. Da dies eine ziemlich häufige Fehlerquelle ist, würde ich dir davon definitiv abraten (macht auch wirklich selten Sinn). Wenn du die Felder in
Delphi-Quellcode:
TErbe
einfach weglässt, kannst du ja trotzdem auf die vererbten Felder aus
Delphi-Quellcode:
TBasis
zugreifen, auch wenn deine Instanz vom Typ
Delphi-Quellcode:
TErbe
ist.
Delphi-Quellcode:
var
  T1: TBaseClass;
  T2: TClass2;
begin
  ..
  // Kompiliert
  T1.CommonTest;
  // Kompiliert auch
  T2.CommonTest;
  T2.OnlyForClass2;
  ..
Bezüglich deines Beispiels würde ich dir btw. auf jeden Fall raten nicht direkt von
Delphi-Quellcode:
TObjectList<T>
abzuleiten, sondern eine dedizierte Klasse zu erstellen, welche lediglich ein Feld vom Typ
Delphi-Quellcode:
TObjectList<T>
beinhaltet. So wie in meinem Beispiel weiter oben.

Benmik 15. Apr 2017 21:12

AW: TObjectList<> - Frage
 
Das verstehe ich. Hab ich jetzt auch nicht verwirklicht.

Was ist der Grund, nicht direkt von
Delphi-Quellcode:
TObjectList
abzuleiten? Darauf würde ich sehr ungern verzichten, da das einiges an Codeänderungen bedeuten würde. Ich brauche die abgeleitete Klasse nur in einer einzigen (größeren) Prozedur.

Zacherl 16. Apr 2017 02:14

AW: TObjectList<> - Frage
 
Zitat:

Zitat von Benmik (Beitrag 1367833)
Was ist der Grund, nicht direkt von
Delphi-Quellcode:
TObjectList
abzuleiten?

Dachte ursprünglich, dass man dann das Constraint auf TBaseClass nicht anwenden kann, aber scheint zu funktionieren, also spricht nichts mehr dagegen :stupid:

himitsu 16. Apr 2017 05:48

AW: TObjectList<> - Frage
 
Mit Klassen geht es am Problemlosesten, vorallem die Einschränkung auf einen bestimmten Grundtypen.
Auch allgemein das Constraint auf Objectinstanzen (class) geht, auch wenn man da dann praktisch nur den Grungconstructor (parameterloses Create) und den Destructor ohne verbiegen nutzen kann.
http://docwiki.embarcadero.com/RADSt...isierte_Typen)

Aber sowas wie "nummerische typen", "ordinale typen", alle strings, alle chars oder sowas kann man vergessen.

Benmik 16. Apr 2017 10:28

AW: TObjectList<> - Frage
 
Frohe Ostern!
Funktioniert alles soweit gut, eine kleine - eher kosmetische - Störung gibt es aber:
Die Objektliste ist mit dem Typ TBasis konstruiert. In TBasis sind alle Felder, auf die sich die Such- und Sortierfunktionen beziehen.
Wenn ich jetzt mit mit einer Instanz von TErbe arbeiten will, muss ich immer eine Typumwandlung TErbe(Objektliste[i]) vornehmen. Lässt sich das beseitigen?

PS: Und noch 'ne Frage: Wenn ich das doch über ein Interface realisieren würde, dann müsste doch jede Klasse die Prozeduren und Funktionen dieses Interfaces implementieren. Was wäre denn damit gewonnen? Ich möchte doch gerade diese Prozeduren nur einmal implementieren und gemeinsam nutzen.

Olli73 16. Apr 2017 11:57

AW: TObjectList<> - Frage
 
Zitat:

Zitat von Benmik (Beitrag 1367851)
Die Objektliste ist mit dem Typ TBasis konstruiert. In TBasis sind alle Felder, auf die sich die Such- und Sortierfunktionen beziehen.
Wenn ich jetzt mit mit einer Instanz von TErbe arbeiten will, muss ich immer eine Typumwandlung TErbe(Objektliste[i]) vornehmen. Lässt sich das beseitigen?

Wenn in TBasis alle benötigten Properties (besser als public Felder) und Methoden deklariert sind, musst du nicht casten.

Brauchst du Methoden, die es nur in einem der TErbe gibt, musst du entweder casten oder zwei Objektlisten mit dem jeweiligen TErbe erstellen.

Benmik 16. Apr 2017 13:10

AW: TObjectList<> - Frage
 
Folgende Konstruktion:
Delphi-Quellcode:
type
  TBasis = class(TObject)
    Var1 : integer;
    Var2 : string;
  end;

type
  TErbe = class(TBasis)
    Var3 : integer;
    Var4 : string;
  end;

type
TListe = class(TObjectList<TBasis>)
public
  procedure SortiereVar1(Wert:integer)
end;

var Erbe:TErbe; Liste:TListe;
Erbe := Liste[0];
Das geht nicht, weil die Liste vom Typ TBasis und nicht TErbe ist. Mit
Delphi-Quellcode:
Erbe := TErbe(Liste[0]);
geht es.

DeddyH 16. Apr 2017 13:28

AW: TObjectList<> - Frage
 
Wieso deklarierst Du die Variable als TErbe, wenn Du nur auf Felder von TBasis zugreifst?

Benmik 16. Apr 2017 13:52

AW: TObjectList<> - Frage
 
TErbe hat gegenüber TBasis zusätzliche Felder, die ich benötige. Alle Felder, auf die die Prozeduren und Funktionen von TListe zugreifen, sind aber in TBasis enthalten. Sie werden auch für TErbe benötigt.

Zacherl 16. Apr 2017 15:28

AW: TObjectList<> - Frage
 
Ich glaube du hast da irgendwo noch einen Logikfehler. Sollte es nicht eher so sein:
Delphi-Quellcode:
type
  TListe<T: TBasis> = class(TObjectList<T>)
  public
    procedure SortiereVar1(Wert:integer)
  end;
Dann hast du nämlich keinerlei Probleme später bei den konkreten Instanzen folgendes zu machen:
Delphi-Quellcode:
var
  List1: TListe<TErbe>;
  List2: TListe<TNochEinErbe>;
  List3: TListe<TBasis>
Besonders, da du ja sagst, dass du in
Delphi-Quellcode:
TListe
eh nur Felder aus
Delphi-Quellcode:
TBasis
verwendest. Dies ist durch das Constraint sehr komfortabel möglich.

Benmik 16. Apr 2017 16:24

AW: TObjectList<> - Frage
 
Ja, irgendwie kann ich mich nicht richtig verständlich machen.
Also vielleicht nochmal. Ich habe folgende Situation:
Delphi-Quellcode:
type
  TTyp = class(TObject)
    Var1 : integer;
    Var2 : string;
    Var3 : Boolean;
    Var4 : TBitmap;
    Var5..Var20
  end;

type
  TTyp2 = class(TBasis)
    Var1 : integer;
    Var2 : string;
    Var5 : integer;
    Var6 : string;
  end;

type
TListe = class(TObjectList<TTyp1>)
public
  procedure SortiereVar1(Wert:integer)
  procedure SortiereVar2(Wert:string
end;
Ich brauche nun für eine bestimmte Aufgabe Var1 und Var2 und die dazugehörigen Prozeduren der TObjectlist, aber zusätzlich noch Var5 und Var6. Var5..20 brauche ich nicht. Das alles ist nun in Typ2 realisiert.
Zurzeit ist Typ2 eine abgeleitete Klasse von Typ1. Damit stehen mir die neuen Felder und die gewünschten Prozeduren der TObjectList zur Verfügung, aber ich schleppe Var5..Var20 mit und muss immer den Typecast
Delphi-Quellcode:
 Erbe := TErbe(Liste[0]) machen.
Wie gesagt, es funktioniert alles, aber ich glaube, dass das besser geht. Die Syntax von
Delphi-Quellcode:
 TListe<T: TBasis> = class(TObjectList<T>)
kannte ich nicht und kann nur mutmaßen, was dahinter steht.

DeddyH 16. Apr 2017 16:53

AW: TObjectList<> - Frage
 
Irgendwie sieht Dein Klassenmodell komisch aus. Sind die Variablen bzw. Felder wirklich in den Ableitungen redeklariert? Wenn ja, wieso? Wenn Deine Objektliste nur auf Felder und Methoden zugreift, die bereits in der Basisklasse deklariert wurden, ist der Typecast unnötig.

Benmik 16. Apr 2017 17:09

AW: TObjectList<> - Frage
 
Nein, nein, die Var1 und Var2 wurden bei Typ2 nur zur Verdeutlichung aufgeführt, dass eine Schnittmenge zum Typ1 besteht; in der wirklichen Deklaration fehlen sie natürlich (siehe auch meine Frage und die Antwort von Zacherl), da sie ja schon in der Vorfahr-Klasse Typ1 enthalten sind.
Dass meine Konstruktion nicht optimal ist, will ich gern glauben.
Im Moment sieht es so aus:
Delphi-Quellcode:
type Typ1<TObject>
Delphi-Quellcode:
type Typ2 = class(Typ1)
Delphi-Quellcode:
type Liste = TObjectlist<Typ1>
.
Ohne Typecast geht es damit nicht, weil der Compiler meckert, die Liste wär vom Typ1 und die Variable vom Typ2.

DeddyH 16. Apr 2017 17:15

AW: TObjectList<> - Frage
 
Welche Variable denn?

Olli73 16. Apr 2017 17:24

AW: TObjectList<> - Frage
 
Sollen in "Liste" Objektinstanzen von Typ1 und Typ2 gespeichert werden oder genügt es dir eine Liste1 vom Typ1 und eine Liste2 vom Typ2 zu haben?

Benmik 16. Apr 2017 17:40

AW: TObjectList<> - Frage
 
@DeddyH:
Delphi-Quellcode:
var Typ2:TTyp2;
begin
  Typ2 := Liste[0];
end;
Compiler: "E2010: Inkompatible Typen TTyp1 und TTyp2". Eigentlich klar, denn die Liste ist ja als
Delphi-Quellcode:
 TObjectlist<Typ1>
deklariert

@Olli73: Naja, in Typ1 sind Felder, die auch Typ2 braucht, und die Objektliste für diese Felder Funktionen und Prozeduren bereitstellt, die auch Typ2 braucht.

Olli73 16. Apr 2017 17:57

AW: TObjectList<> - Frage
 
Zitat:

Zitat von Benmik (Beitrag 1367884)
@Olli73: Naja, in Typ1 sind Felder, die auch Typ2 braucht, und die Objektliste für diese Felder Funktionen und Prozeduren bereitstellt, die auch Typ2 braucht.

Die TList ist natürlich nur 1 mal da. Aber willst du nur 1 Instanz "Liste" davon, um Instanzen beider Typen darin zu speichern oder können es auch 2 Instanzen (Liste1 und Liste2) der TList sein und speicherst Typ1 in Liste 1 und Typ2 in Liste2?

Benmik 16. Apr 2017 18:15

AW: TObjectList<> - Frage
 
Instanzen der Objektliste werden bei vielen Gelegenheiten erzeugt, und sie enthielten bisher immer Elemente vom Typ1, so dass es bisher ja auch keine Probleme gab.
Für eine bestimmte Routine brauche ich aber einen zum Teil anderen Variablensatz, als ihn Typ1 bietet.
Ich könnte nun einfach eine Objektliste vom Typ2 definieren und deklarieren, aber die Objektliste des Typ1 definiert viele Routinen, die auch Typ2 braucht. Diese ganzen Routinen müsste ich in der Objektliste Typ2 duplizieren. Da suche ich nach einem einfacheren Weg.
Nochmal, die Ableitung des Typ2 von Typ1 und das Typecasting der Objektliste zu einer solchen vom Typ2 funktioniert ja; ich würde nur gern wissen, ob es eine elegantere Möglichkeit gibt und dabei mein Wissen noch erweitern.

Zacherl 16. Apr 2017 18:25

AW: TObjectList<> - Frage
 
Zitat:

Zitat von Benmik (Beitrag 1367895)
Nochmal, die Ableitung des Typ2 von Typ1 und das Typecasting der Objektliste zu einer solchen vom Typ2 funktioniert ja; ich würde nur gern wissen, ob es eine elegantere Möglichkeit gibt und dabei mein Wissen noch erweitern.

Ja gibt es :-D Siehe meinen letzten Post. Du musst den generischen Parameter an deine Klasse attachen und NICHT hardcoded an
Delphi-Quellcode:
TObjectList
. Also
Delphi-Quellcode:
type TMyObjectList<T: TBaseClass> = class(TObjectList<T>)
statt
Delphi-Quellcode:
type TMyObjectList = class(TObjectList<TBaseClass>)
.

Dann verwendest du für die Typ1/TBasisClass Listen die Deklaration
Delphi-Quellcode:
var List: TMyObjectList<TBaseClass>
und für die Typ2/TDerivedClass Listen entsprechend
Delphi-Quellcode:
var List: TMyObjectList<TDerivedClass>
. Im zweiten Falle sind dann auch alle Objekte der Liste vom Typ
Delphi-Quellcode:
TDerivedClass
, so dass du dir den Typecast sparen kannst.

Benmik 16. Apr 2017 18:44

AW: TObjectList<> - Frage
 
OK Zacherl, das wird ausprobiert. Hatte das schon mal versucht, aber da meckerte der Compiler haufenweise Code an, das wurde mir zuviel. Muss jetzt weg, aber vertiefe mich mal darin. Danke.


Alle Zeitangaben in WEZ +1. Es ist jetzt 02:15 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz