Ich verwende derzeit noch Delphi 2009, also dachte ich, ich würde ein paar andere Möglichkeiten hinzufügen, um eine generische Klasse zu erweitern. Diese sollten in neueren Versionen von Delphi genauso gut funktionieren. Schauen wir uns an, wie es aussehen würde, eine ToArray
Methode zu einer List-Klasse.
Abfangjäger Klassen
Interceptor-Klassen sind Klassen, die den gleichen Namen wie die Klasse tragen, von der sie erben:
TList<T> = class(Generics.Collections.TList<T>)
public
type
TDynArray = array of T;
function ToArray: TDynArray;
end;
function TList<T>.ToArray: TDynArray;
var
I: Integer;
begin
SetLength(Result, self.Count);
for I := 0 to Self.Count - 1 do
begin
Result[I] := Self[I];
end;
end;
Beachten Sie, dass Sie den vollständig qualifizierten Namen verwenden müssen, Generics.Collections.TList<T>
als Vorfahre. Andernfalls erhalten Sie E2086 Type '%s' is not completely defined
.
Der Vorteil dieser Technik besteht darin, dass Ihre Erweiterungen weitgehend transparent sind. Sie können Instanzen der neuen TList überall dort verwenden, wo das Original verwendet wurde.
Diese Technik hat zwei Nachteile:
- Es kann bei anderen Entwicklern Verwirrung stiften, wenn sie nicht wissen, dass Sie eine bekannte Klasse neu definiert haben.
- Sie kann nicht für eine versiegelte Klasse verwendet werden.
Die Verwirrung kann durch eine sorgfältige Benennung der Einheiten und die Vermeidung der Verwendung der "Original"-Klasse an derselben Stelle wie Ihre Abfangklasse gemildert werden. Versiegelte Klassen sind in den von Embarcadero gelieferten rtl/vcl-Klassen kein großes Problem. Ich habe im gesamten Quellbaum nur zwei versiegelte Klassen gefunden: TGCHandleList (wird nur im nicht mehr existierenden Delphi.NET verwendet) und TCharacter. Es kann jedoch zu Problemen mit Bibliotheken von Drittanbietern kommen.
Le site Dekorateur Muster
Mit dem Dekoratormuster können Sie eine Klasse dynamisch erweitern, indem Sie sie mit einer anderen Klasse umhüllen, die ihre öffentliche Schnittstelle erbt:
TArrayDecorator<T> = class abstract(TList<T>)
public
type
TDynArray = array of T;
function ToArray: TDynArray; virtual; abstract;
end;
TArrayList<T> = class(TArrayDecorator<T>)
private
FList: TList<T>;
public
constructor Create(List: TList<T>);
function ToArray: TListDecorator<T>.TDynArray; override;
end;
function TMyList<T>.ToArray: TListDecorator<T>.TDynArray;
var
I: Integer;
begin
SetLength(Result, self.Count);
for I := 0 to Self.Count - 1 do
begin
Result[I] := FList[I];
end;
end;
Auch hier gibt es Vor- und Nachteile.
Vorteile
- Sie können die Einführung der neuen Funktion aufschieben, bis sie tatsächlich benötigt wird. Sie müssen eine Liste in ein Array umwandeln? Konstruieren Sie eine neue TArrayList und übergeben Sie eine TList oder einen Abkömmling als Parameter im Konstruktor. Wenn Sie fertig sind, verwerfen Sie einfach die TArrayList.
- Sie können zusätzliche Dekoratoren erstellen, die weitere Funktionen hinzufügen, und Dekoratoren auf verschiedene Weise kombinieren. Sie können damit sogar Mehrfachvererbung simulieren, obwohl Schnittstellen immer noch einfacher sind.
Benachteiligungen
- Es ist ein wenig komplexer zu verstehen.
- Das Anwenden von mehreren Dekoratoren auf ein Objekt kann zu langatmigen Konstruktorketten führen.
- Wie bei Abfangjägern können Sie eine versiegelte Klasse nicht erweitern.
Nebenbemerkung
Es scheint also, dass, wenn Sie eine Klasse fast unmöglich zu erweitern machen wollen, machen es eine versiegelte generische Klasse. Dann können Klassenhelfer sie nicht berühren und es kann nicht von ihr geerbt werden. Die einzige Möglichkeit, die bleibt, ist das Wrapping.