![]() |
Alternative zu Typecast => IInterface?
Hallo Leute,
ich bin die letzten Wochen immer wieder hier im Forum auf Interfaces gestoßen, und frage mich, ob diese meinen Code sicherer/eleganter machen könnten... Folgende Ausgangssituation: Habe eine Basisklasse TSVFXCustomCmd. Dieser dient als Vorfahr verschiedener Klassen, die u.a unterschiedliche Routinen zur Verfügung stellen. Die Klasse TSVFXVisualCmd deklariert beispielsweise eine Routine mit dem Namen Prozess(), die in den abgeleiteten Routinen überschrieben werden. Alle diese Klassen von einer abgeleiteten Containerklasse vom TObjectList verwaltet (OwnsObject ist True). Keine Generics im Moment. Klassenableitungen TSVFXCustomCmd <= Basisklasse, verschiedene Properties TSVFXVisualCmd <= abgeleitet von TSVFXCustomCmd, stellt verschiedene Basiskommandos zur Verfügung TSVFXMoveTo <= abgeleitet von TSVFXVisualCmd, Pfadkommando .. TSVFXQBezier <= abgeleitet von TSVFXVisualCmd, Pfadkommando .. TSVFXCircle <= abgeleitet von TSVFXVisualCmd, Primitivekommando .. TSVFXTransformCmd <= abgeleitet von TSVFXCustomCmd, stellt verschiedene Basiskommandos zur Verfügung TSVFXScale <= abgeleitet von TSVFXTransformCmd TSVFXRotate <= abgeleitet von TSVFXTransformCmd .. TSVFXAnimateCmd <= abgeleitet von TSVFXCustomCmd, stellt verschiedene Basiskommandos zur Verfügung .. TSVFXColorCmd <= abgeleitet von TSVFXCustomCmd, stellt verschiedene Basiskommandos zur Verfügung .. Es kommen immer wieder neue Befehle hinzu, einige Routinen müssen jedesmal um Typecasts erweitert werden, das hätte ich mir gerne gespart. Beim Abarbeiten der Objektliste werden objektspezifisch verschiedene Kommandos ausgeführt. Momentan vergleiche ich jedes Objekt mit einem Typecast gegen einen Objekttyp und starte dann die Routinen beispielsweise wie folgt: Ausgangsszenario
Code:
Wunschszenarioif (Self[i]) is TSVFXVisualCommand) then begin (** TSVFXMoveTo **) if Self[i] is TSVFXMoveTo then begin TSVFXMoveTo(Self[i]).Process (APath); end; .. .. end;
Code:
Diese Typecasts gegen KlassenTypen <TSVFXMoveTo(Self[i]).Process (APath);> hätte ich teilweise gerne vermieden. Bei einem Typecast gegen TSVFXVisualCommand wird verständlicherweise nicht die vom eigentlichen Objekt überschriebene Override Routine aufgerufen. Deklariere ich das Interface in der Klasse TSVFXVisualCommand, so muss ich das nach meinem derzeitigen Wissensstand auch dort implementieren, somit bringt dies nichts. Implementiere ich dieses Interface in den abgeleiteten Klassen, so lande ich wieder beim Typecast...if (Self[i]) is TSVFXVisualCommand) then TSVFXVisualCommand(Self[i])).Process (APath); <= abgeleiteter Befehl soll ausgeführt werden. Höchstwahrscheinlich übersehe ich hier etwas wesentliches, bin generell auf dem Holzweg, oder Typecast ist und bleibt mein Ding... Gruß, Peter |
AW: Alternative zu Typecast => IInterface?
Zitat:
Ich verstehe nicht weshalb die ganzen Typecasts sein müssen. Du hast doch mal eine Oberklasse, das ist doch schon mal ordentlich was wert. Du kannst auf Unterklassen lustig typecasten, aber in der Implementierung wird immer die "unterste" aufgerufen:
Delphi-Quellcode:
Was möchtest du jetzt mit Interfaces erreichen? Ich glaube mir müsste man das jetzt noch mal in einfachen Worten (am besten mit vielen Vokalen) erklären...
program Project11;
{$APPTYPE CONSOLE} {$R *.res} type TBird = class public procedure makeNoise(); virtual; end; TDuck = class(TBird) public procedure makeNoise(); override; end; TCliffracer = class(TBird) public procedure makeNoise(); override; end; procedure TCliffracer.makeNoise(); begin WriteLn('Skreeeeee'); end; procedure TDuck.makeNoise; begin WriteLn('Quack!'); end; procedure TBird.makeNoise(); begin WriteLn( '(generic bird sounds)' ); end; var bird: TBird; begin bird := TDuck.Create(); bird.makeNoise(); // Quack! TBird(bird).makeNoise(); // Quack! TDuck(bird).makeNoise(); // Quack! if (bird is TCliffracer) then TCliffracer(bird).makeNoise() else WriteLn('It''s not a cliffracer'); readln; end. |
AW: Alternative zu Typecast => IInterface?
Wieso solltest Du bei Verwendung von Interfaces wieder beim Typecast landen? Du musst doch lediglich ermitteln, ob die aktuelle Instanz ein bestimmtes Interface implementiert und das dann benutzen. Dafür musst Du noch nicht einmal eine bestimmte Klassenhierarchie einhalten, da der Verwender nur die Interfaces sieht und nicht die Klasse.
Delphi-Quellcode:
procedure TIrgendwas.Work(const Intf: IBasicInterface);
var FirstIntf: IFirstIntf; SecondIntf: ISecondIntf; begin Intf.DoBasicWork; if Supports(Intf, IFirstIntf, FirstIntf) then FirstIntf.DoSomeWork; if Supports(Intf, ISecondIntf, SecondIntf) then SecondIntf.DoSomeOtherWork; end; |
AW: Alternative zu Typecast => IInterface?
Zitat:
|
AW: Alternative zu Typecast => IInterface?
Zitat:
Je nach Objekttyp gibt es in der abgeleiteten Basisklasse unterschiedliche Befehle, die ausgeführt werden sollen. Alle Ableitungen von TSVFXVisualCmd haben beispielsweise die Routine Process, alle Ableitungen von TSVFXAnimateCmd haben die Routine Animate zur Verfügung. Je nach Parentklasse soll der Aufruf unterschieden werden. Wenn ich typengecasted TSVFXVisualCmd().Process aufrufe, wird jedoch explizit die Routine dieser Klasse aufgerufen, und nicht vom Nachfolger als überschrieben definierte Routine, weil ich ja nicht beispielsweise gegen TSVFXMoveTo caste. (Basisroutine ist als Virtual deklariert, Nachfolger überschreibt mittels Override). Mit IInterface sollte ich nun das Problem eleganter umgehen können... |
AW: Alternative zu Typecast => IInterface?
Ich denke auch, wie vom Günther angedeutet, dass Du Deine Methoden nicht korrekt mit virtual und override deklariert hast.
(Dann sollte der Compiler Warnungen ausgeben im Sinne "Methode X der Klasse Y verbirgt Methode X der Basisklasse A" oder ähnliches) Interfaces sind nützlich, bedingen aber auch einige Änderungen und zusätzlichen Aufwand. Den kannst Du Dir evtl. sparen, wenn Du die Methoden der Basisklasse und der Ableitungen korrekt implementierst. Zeig sonst evtl. mal Deine Klassendeklaration... |
AW: Alternative zu Typecast => IInterface?
Zitat:
Darüber hinaus würde ich dir empfehlen das Command-Pattern anzuschauen - bzw. wenn dir das zu abstrakt ist die TAction-Implementierung in Delphi. Wenn ich das richtig verstanden habe, willst / brauchst Du genau so was... |
AW: Alternative zu Typecast => IInterface?
Zitat:
Na zumindest blicke ich jetzt besser bei den Interfaces durch... |
AW: Alternative zu Typecast => IInterface?
Aber Jünge!
Du müsstest doch eine Compiler-Warnung bekommen
Delphi-Quellcode:
in Form von
type
TBase = class public procedure stuff(); virtual; end; TSub = class(TBase) public procedure stuff(); virtual; end; Zitat:
Oder? |
AW: Alternative zu Typecast => IInterface?
Zitat:
Wie gesagt hatte ich mir die Warnungen nicht angesehen, dort stands ja drinnen... [dcc32 Warnung] SVFXCommands.pas(189): W1010 Methode 'Process' verbirgt virtuelle Methode vom Basistyp 'TSVFXVisualCmd'
Code:
(******************************************************************************)
(******************************************************************************) (** TSVFXVisualCmd **) (******************************************************************************) (******************************************************************************) TSVFXVisualCmd = Class (TSVFXCustomCmd) private FGroupIndex : UInt32; FConstraints : TSVFXSizeConstraints; FShift : TFloatPoint; FConstraintValue : TFloatPoint; protected procedure DoConstraintsChanged (Sender : TObject); Virtual; function GetConstrainedSize (Const Value: TFloatPoint) : TFloatPoint; Virtual; function GetPoint () : TPointInfo; Virtual; Abstract; function GetPreviousPoint () : TPointInfo; Virtual; function GetSize : TFloatPoint; Virtual; function Process (APath : TFlattenedPath) : Boolean; Virtual; Abstract; property GroupIndex : UInt32 read FGroupIndex write FGroupIndex; property Constraints : TSVFXSizeConstraints read fConstraints write fConstraints; public Constructor Create (AOwner : TSVFXCommands; Const ADescription : String); Override; Destructor Destroy; Override; procedure UpdateShift (Const Value : TFloatPoint); Virtual; Abstract; procedure UpdateValues; Virtual; Abstract; (** Der Befehl UpdateValues aktualisiert die "Arbeitsvariablen_", die u.a zur Pfadbildung **) (** verwendet werden. **) function ValuesAsText () : String; Virtual; property ConstraintValue : TFloatPoint read fConstraintValue; property Size : TFloatPoint read GetSize; end; (******************************************************************************) (******************************************************************************) (** TSVFXMoveTo - TSVFXCommand **) (** Bewegt den Stift an die Position Startpoint **) (******************************************************************************) (******************************************************************************) TSVFXMoveTo = Class (TSVFXVisualCmd) private fPoint : TFloatPoint; fPoint_ : TFloatPoint; FDirections : TSVFXDirections; procedure SetPoint (Const Value : TFloatPoint); protected procedure AssignTo (Dest : TPersistent); Override; function Read1000 (AStream : TStream) : Integer; Override; function GetPoint : TPointInfo; Override; function GetPreviousPoint : TPointInfo; Override; public Constructor Create(AOwner : TSVFXCommands; Const ADescription : String); Override; function LoadFromStream (AStream : TStream) : Integer; Override; function SaveToStream (AStream : TStream) : Integer; Override; function ValuesAsText () : String; Override; procedure UpdateShift (Const Value : TFloatPoint); Override; procedure UpdateValues (); Override; function Process (APath : TFlattenedPath) : Boolean; virtual; property Point : TFloatPoint read fPoint write SetPoint; property Directions : TSVFXDirections read FDirections write FDirections; property Flag; property GroupIndex; end; |
Alle Zeitangaben in WEZ +1. Es ist jetzt 02:50 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz