Klassenhelfer für generische Klasse?

7

Ich benutze Delphi 2009. Ist es möglich, einen Klassenhelfer für eine generische Klasse zu schreiben, d. h. für TQueue. Das offensichtliche

%Vor%

funktioniert nicht, noch

%Vor%     
jpfollenius 21.10.2009, 11:27
quelle

3 Antworten

10

Wie in der Delphi-Hilfe dokumentiert, sind Klassenhelfer nicht für allgemeine Zwecke gedacht und werden fälschlicherweise als eine Anzahl von Einschränkungen oder sogar Fehlern betrachtet.

Dennoch gibt es eine - aus meiner Sicht falsche und gefährliche - Wahrnehmung, dass dies ein legitimes Werkzeug im allgemeinen "Toolkit" ist. Ich habe über gebloggt, warum das falsch ist und anschließend darüber, wie Sie die Gefahren mildern können von einem sozial verantwortlichen Kodierungsmuster folgen (obwohl selbst dies nicht kugelsicher ist).

>

Sie können die Wirkung eines Klassenhelfers ohne any dieser Fehler oder Einschränkungen oder (am wichtigsten) Risiken erreichen, indem Sie eine harte Umwandlung in eine "Pseudo" -Ausführung verwenden. Klasse, die von der Klasse abgeleitet ist, die Sie erweitern möchten. d. h. statt:

%Vor%

verwenden

%Vor%

Genau wie bei einem "formalen" Helfer instanziieren Sie diese Klasse TFooHelper niemals. Sie verwenden sie nur, um die Klasse TFoo zu mutieren, außer in diesem Fall müssen Sie sei explizit. Wenn Sie in Ihrem Code eine Instanz eines TFoo mit Ihren "Helfer" -Methoden verwenden müssen, müssen Sie hart werfen:

%Vor%

Nachteile:

  1. Sie müssen sich an dieselben Regeln halten, die für Helfer gelten - keine Mitgliedsdaten usw. (nicht wirklich ein Nachteil, außer dass der Compiler Sie nicht "erinnert").

  2. Sie müssen explizit umwandeln, um Ihren Helfer zu verwenden

  3. Wenn Sie einen Helper verwenden, um geschützte Member verfügbar zu machen, müssen Sie den Helper in derselben Einheit deklarieren, in der Sie ihn verwenden (es sei denn, Sie stellen eine öffentliche Methode zur Verfügung, die die erforderlichen geschützten Member verfügbar macht)

Vorteile:

  1. Absolut kein Risiko, dass Ihr Helfer kaputt geht, wenn Sie einen anderen Code verwenden, der derselben Basisklasse "hilft"

  2. Das explizite Typecasting macht es in Ihrem "Consumer" -Code deutlich, dass Sie mit der Klasse auf eine Weise arbeiten, die nicht direkt von der Klasse selbst unterstützt wird, anstatt diese Tatsache hinter einem syntaktischen Zucker zu verstecken und zu verstecken.

Es ist nicht so "sauber" wie ein Klassenhelfer, aber in diesem Fall ist die "sauberere" Herangehensweise eigentlich nur das Durcheinander unter dem Teppich und wenn jemand den Teppich stört, endet ein größeres Durcheinander als du begonnen hast.

    
Deltics 21.10.2009, 18:33
quelle
11

Ich benutze Delphi 2009 noch, 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 gleich gut funktionieren. Sehen wir uns an, wie es aussehen würde, wenn wir eine ToArray -Methode zu einer List-Klasse hinzufügen würden.

Interceptor Klassen

Interceptor-Klassen sind Klassen, die denselben Namen wie die Klasse erhalten, von der sie erben:

%Vor%

Beachten Sie, dass Sie den vollständig qualifizierten Namen Generics.Collections.TList<T> als Vorgänger verwenden müssen. Andernfalls erhalten Sie E2086 Type '%s' is not completely defined .

Der Vorteil dieser Technik besteht darin, dass Ihre Erweiterungen größtenteils transparent sind. Sie können Instanzen der neuen TList überall dort verwenden, wo das Original verwendet wurde.

Diese Technik hat zwei Nachteile:

  • Es kann für andere Entwickler Verwirrung stiften, wenn sie nicht wissen, dass Sie eine vertraute Klasse neu definiert haben.
  • Es kann nicht in einer versiegelten Klasse verwendet werden.

Die Verwirrung kann durch sorgfältige Benennung von Einheiten gemildert werden und die Verwendung der "Original" -Klasse an der gleichen Stelle wie Ihre Interceptor-Klasse vermieden werden. Versiegelte Klassen sind in den von Embarcadero bereitgestellten rtl / vcl-Klassen kein großes Problem. Ich habe nur zwei Siegel gefunden, die in den gesamten Quellbaum eingeordnet wurden: TGCHandleList (nur im jetzt nicht mehr existierenden Delphi.NET) und TCharacter. Möglicherweise treten jedoch Probleme mit Bibliotheken von Drittanbietern auf.

Das Dekorator Muster

Mit dem Decorator-Muster können Sie eine Klasse dynamisch erweitern, indem Sie sie mit einer anderen Klasse umschließen, die ihre öffentliche Schnittstelle erbt:

%Vor%

Auch hier gibt es Vor- und Nachteile.

Vorteile

  • Sie können die Einführung der neuen Funktion verzögern, bis sie tatsächlich benötigt wird. Müssen Sie eine Liste an ein Array ausgeben? Konstruieren Sie eine neue TArrayList, die eine TList oder einen Nachkommen als Parameter im Konstruktor übergibt. Wenn Sie fertig sind, verwerfen Sie einfach die TArrayList.
  • Sie können zusätzliche Dekoratoren erstellen, die mehr Funktionen hinzufügen und Dekoratoren auf unterschiedliche Weise kombinieren. Sie können es sogar verwenden, um Mehrfachvererbung zu simulieren, obwohl Schnittstellen noch einfacher sind.

Nachteile

  • Es ist ein bisschen komplexer zu verstehen.
  • Das Anwenden mehrerer Dekoratoren auf ein Objekt kann zu ausführlichen Konstruktorketten führen.
  • Wie bei Interzeptoren können Sie keine versiegelte Klasse erweitern.

Seitenhinweis

So scheint es, dass wenn Sie eine Klasse fast unmöglich machen möchten, machen Sie es zu einer versiegelten generischen Klasse. Dann können Klassenhelfer es nicht berühren und es kann nicht geerbt werden. Über die einzige verbleibende Option ist das Wrapping.

    
Kenneth Cochran 15.09.2011 20:55
quelle
7

Soweit ich das beurteilen kann, gibt es keine Möglichkeit, einen Klassenhelfer in eine generische Klasse zu packen und sie kompilieren zu lassen. Sie sollten dies QC als Fehler melden.

    
Mason Wheeler 21.10.2009 11:35
quelle