AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Thema durchsuchen
Ansicht
Themen-Optionen

Klasseninstanz zur Laufzeit bestimmen

Ein Thema von Delbor · begonnen am 1. Aug 2015 · letzter Beitrag vom 4. Aug 2015
Antwort Antwort
Benutzerbild von Sir Rufo
Sir Rufo

Registriert seit: 5. Jan 2005
Ort: Stadthagen
9.454 Beiträge
 
Delphi 10 Seattle Enterprise
 
#1

AW: Klasseninstanz zur Laufzeit bestimmen

  Alt 2. Aug 2015, 07:11
Nun ja, bei XE4 gibt es natürlich auch schon nettere Arten, damit umzugehen
Delphi-Quellcode:
unit Unit1;

interface

uses
  {System.}Generics.Collections,
  {System.}SysUtils;

type
  TObjectHandler = class abstract
  private type
    TAction = TProc<TObject>;
  private
    FRoutes: TDictionary<TClass, TAction>;
  protected type
    TRoute<T> = procedure( Argument: T ) of object;
  protected
    procedure RegisterRoute<T: class>( ARoute: TRoute<T> );
    procedure DoRaise( Argument: TObject );
  end;

  TFoo = class

  end;

  TBar = class

  end;

  TFooBar = class( TObjectHandler )
  private
    procedure Apply( Argument: TFoo ); overload;
    procedure Apply( Argument: TBar ); overload;
  public
    constructor Create( );

    procedure Handle( Argument: TObject );
  end;

implementation

{ TObjectHandler }

procedure TObjectHandler.DoRaise( Argument: TObject );
var
  LAction: TAction;
begin
  if FRoutes.TryGetValue( Argument.ClassType, LAction ) then
    LAction( Argument )
  else
    raise ENotImplemented.CreateFmt( 'Handler für %s fehlt', [ Argument.ClassName ] );
end;

procedure TObjectHandler.RegisterRoute<T>( ARoute: TRoute<T> );
begin
  FRoutes.Add( T,
    procedure( Argument: TObject )
    begin
      ARoute( Argument as T );
    end );
end;

{ TFooBar }

procedure TFooBar.Apply( Argument: TFoo );
begin

end;

procedure TFooBar.Apply( Argument: TBar );
begin

end;

constructor TFooBar.Create;
begin
  inherited Create;
  RegisterRoute<TFoo>( Apply );
  RegisterRoute<TBar>( Apply );
end;

procedure TFooBar.Handle( Argument: TObject );
begin
  DoRaise( Argument );
end;

end.
Kaum macht man's richtig - schon funktioniert's
Zertifikat: Sir Rufo (Fingerprint: ‎ea 0a 4c 14 0d b6 3a a4 c1 c5 b9 dc 90 9d f0 e9 de 13 da 60)
  Mit Zitat antworten Zitat
Dejan Vu
(Gast)

n/a Beiträge
 
#2

AW: Klasseninstanz zur Laufzeit bestimmen

  Alt 2. Aug 2015, 14:08
Zu sehr verwirren wollte ich den TE nun auch nicht.

'Case' (oder hier: if/else-Schlangen) sind zwar 'böse', aber in Fabrikmethoden durchaus erlaubt. Denn es ist ja nun kein Mehrwert ggü dem if/else bzw. 'case' (geht hier leider nicht), eine 1:1 Abbildung in eine Liste (oder Dictionary) zu stopfen.

Obwohl.. bei endlose if/else-Wicklungen würde ich nicht drauf beharren.
  Mit Zitat antworten Zitat
Benutzerbild von Sir Rufo
Sir Rufo

Registriert seit: 5. Jan 2005
Ort: Stadthagen
9.454 Beiträge
 
Delphi 10 Seattle Enterprise
 
#3

AW: Klasseninstanz zur Laufzeit bestimmen

  Alt 2. Aug 2015, 14:20
Wenn ich CleanCode haben möchte, dann nehmen ich so ein Routing-Dictionary.

(Gerade fällt mir auf, dass die Basis-Klasse keinen Destruktor hat ... ts ts ts)
Kaum macht man's richtig - schon funktioniert's
Zertifikat: Sir Rufo (Fingerprint: ‎ea 0a 4c 14 0d b6 3a a4 c1 c5 b9 dc 90 9d f0 e9 de 13 da 60)
  Mit Zitat antworten Zitat
Dejan Vu
(Gast)

n/a Beiträge
 
#4

AW: Klasseninstanz zur Laufzeit bestimmen

  Alt 2. Aug 2015, 15:59
Wenn ich CleanCode haben möchte, dann nehmen ich so ein Routing-Dictionary
Kann man. Muss man nicht.
Zitat von Robert C. Martin in 'Clean Code':
...is to bury the switch statement in the basement of an ABSTRACT FACTORY and never let anyone see it. The factory will use the switch statement to create appropriate instances ... My general rule for switch statements is that they can be tolerated if they appear only once..
  Mit Zitat antworten Zitat
idefix2

Registriert seit: 17. Mär 2010
Ort: Wien
1.027 Beiträge
 
RAD-Studio 2009 Pro
 
#5

AW: Klasseninstanz zur Laufzeit bestimmen

  Alt 2. Aug 2015, 16:53
'Case' (oder hier: if/else-Schlangen) sind zwar 'böse'
Was, jetzt ist case also auch schon böse geworden?

Man kanns übertreiben...
  Mit Zitat antworten Zitat
Benutzerbild von Sir Rufo
Sir Rufo

Registriert seit: 5. Jan 2005
Ort: Stadthagen
9.454 Beiträge
 
Delphi 10 Seattle Enterprise
 
#6

AW: Klasseninstanz zur Laufzeit bestimmen

  Alt 2. Aug 2015, 17:08
'Case' (oder hier: if/else-Schlangen) sind zwar 'böse'
Was, jetzt ist case also auch schon böse geworden?

Man kanns übertreiben...
Bitte auch den Kontext lesen und im selbigen verstehen.
Kaum macht man's richtig - schon funktioniert's
Zertifikat: Sir Rufo (Fingerprint: ‎ea 0a 4c 14 0d b6 3a a4 c1 c5 b9 dc 90 9d f0 e9 de 13 da 60)
  Mit Zitat antworten Zitat
Delbor

Registriert seit: 8. Okt 2006
Ort: St.Gallen/Schweiz
1.192 Beiträge
 
Delphi 11 Alexandria
 
#7

AW: Klasseninstanz zur Laufzeit bestimmen

  Alt 2. Aug 2015, 19:14
Hi zusammen

Sorry, wenn ich auf Sir Rufos Vorschlag bisher nicht eingegangen bin; der Grund liegt vor allem darin, dass ich bisher sehr wenig mit Generics arbeite, da ich die Dinger zu wenig durchschaue.
Eigentlich ist die einzige generische Klasse, die ich bisher benutze, eine Objectliste, die mir einst DeddyH vorgeschlagen hat. Ein weiterer seiner Vorschläge betraf die Verwendung einer Class Factory.Und so sieht das Ding heute bei mir aus :

Delphi-Quellcode:
uses Generics.Collections, Vcl.Forms, System.Classes, System.SysUtils;

type
  EFrameNotRegistered = class(Exception);
  TFrameClass = class of TFrame;

  TFrameFactory = class abstract
  strict private
    class var FAssociations: TDictionary<string, TFrameClass>;
    class constructor Create;
    class destructor Destroy;
  public
    class procedure RegisterFrameClass(const Extension: string; FrameClass: TFrameClass);
    class function GetRegisteredFrameClass(const Extension: string; AOwner: TComponent): TFrame;
  end;

implementation

{ TFrameFactory }

class constructor TFrameFactory.Create;
begin
  FAssociations := TDictionary<string, TFrameClass>.Create;
end;

class destructor TFrameFactory.Destroy;
begin
  FAssociations.Free;
end;

class function TFrameFactory.GetRegisteredFrameClass(const Extension: string;
  AOwner: TComponent): TFrame;
  var AFrameClass: TFrameClass; //TCustomFrameClass
begin
  if FAssociations.TryGetValue(AnsiLowerCase(Extension), AFrameClass) then
    Result := AFrameClass.Create(AOwner)
  else
    raise EFrameNotRegistered.CreateFmt('Für die Endung %s ist keine Frameklasse registriert.', [Extension]);
end;

class procedure TFrameFactory.RegisterFrameClass(const Extension: string;
  FrameClass: TFrameClass);
begin
  FAssociations.AddOrSetValue('.' + AnsiLowerCase(Extension), FrameClass);
end;

end.
Meinen Frames muss ich dann noch folgendes verpassen:
Delphi-Quellcode:
initialization
  TFrameFactory.RegisterFrameClass('css', TCSSFrame);
Dein Vorschlag ist offenbar das generische Gegenstück zu dieser Fabrikklasse, und wenn mich meine bisherigen Kenntnisse der Generics nicht täuschen, könnte ich da jede Klasse registrieren, die, in deinem Beispiel, von TFoo, bzw. TBar erbt oder selbst von einem dieser Typen ist.
Somit könnte ich da jeden meiner Eventhandler registrieren. Hab ich das richtig verstanden?

Gruss
Delbor
Roger
Man muss und kann nicht alles wissen - man muss nur wissen, wo es steht.
Frei nach Albert Einstein
http://roase.ch
  Mit Zitat antworten Zitat
Delbor

Registriert seit: 8. Okt 2006
Ort: St.Gallen/Schweiz
1.192 Beiträge
 
Delphi 11 Alexandria
 
#8

AW: Klasseninstanz zur Laufzeit bestimmen

  Alt 2. Aug 2015, 14:39
Hi zusammen

Vielen Dank für eure Antworten!
@Dejan Vu:
Delphi-Quellcode:
procedure TCssAttriTLBXFrame.CmbxAttributesCloseUp(Sender: TObject);
begin
   FActiveAttribut := TAttributsClass(CmbxAttributes.Items.Objects[CmbxAttributes.ItemIndex]);
  Label1.Caption := FActiveAttribut.ClassName; //FActiveAttribut.AttributName; CmbxAttributes.Items[CmbxAttributes.ItemIndex];

end;
Hier entspricht FActiveAttribut deiner Variablen 'Attribut' in der Prozedur CreateEvent. Als ClassName wird mir hier allerdings TAttributClass zurückgegeben. Gebe ich im Label FActiveAttribut.AttributName aus, erhalte ich allerdings den von mir an die Instanz übergebenen String. Das bedeutet aber auch: die Info über die Klasseninstanz ist in meiner Feldvariablen enthalten - das zeigt ja auch dein Code mit der Abfrage:
  if Attribut=FCommentAttri then result := FCSSCommentEvent Deshalb denke ich, die Info ist im Property 'Tipinfo' von Tpersistent-Nachfolgern enthalten. Die Frage ist (oder war) nur: wie komme ich da ran?
Zitat:
...denn wenn das 'CommentEvent' gefeuert wird, ist ja klar, das mit den CommitAttributen etwas los ist, ergo muss man das Attribut nicht übergeben.
Doch, muss ich, da die Klasse die neuen, und wenn die nicht geändert wurden, die alten Werte enthält. Die Synhighlither enthalten propertys gleichen Namens wie die von mir erstellten Instanzen, sind aber vom Tip der Klasse TSynHighlighterAttributes. So zum Beispiel für TSynCssSyn:
Delphi-Quellcode:
    fCommentAttri: TSynHighlighterAttributes;
    fPropertyAttri: TSynHighlighterAttributes;
    fKeyAttri: TSynHighlighterAttributes;
    fSpaceAttri: TSynHighlighterAttributes;

    fStringAttri: TSynHighlighterAttributes;
    fColorAttri: TSynHighlighterAttributes;
    fNumberAttri: TSynHighlighterAttributes;
    fSymbolAttri: TSynHighlighterAttributes;

    fTextAttri: TSynHighlighterAttributes;
    fValueAttri: TSynHighlighterAttributes;
    fUndefPropertyAttri: TSynHighlighterAttributes;
    fImportantPropertyAttri: TSynHighlighterAttributes;
Ein Auszug aus der dfm:
Delphi-Quellcode:
    AndAttri.Background = clRed
    CommentAttri.Foreground = clOlive
    CommentAttri.Style = [fsBold, fsItalic]
    IdentifierAttri.Foreground = clBlue
    IdentifierAttri.Style = [fsBold, fsUnderline]
    KeyAttri.Foreground = clBlue
    SpaceAttri.Foreground = clMoneyGreen
    SpaceAttri.Style = [fsUnderline]
    SymbolAttri.Foreground = clGray
    TextAttri.Foreground = clRed
    TextAttri.Style = [fsItalic]
    UndefKeyAttri.Background = clYellow
    ValueAttri.Background = clSilver
Das sind die Werte, die meine Klasse übergeben muss.

Delphi-Quellcode:
Procedure TMyForm.CallEventHandler (Event : TAttributEvent; Attribut : TAttributsClass);
Begin
  if Assigned (Event) Then
    Event(Self, Attribut);
end;
Das heisst: im Eventhandler, der diesen Event entgegennimmt, muss ich erstmal die übergebene Instanz identifizieren. Also eigentlich das Gegenstück zu deiner Prozedur CreateEvent schreiben und dann an passender Stelle die Zuweisung machen - pro identifizierter Instanz je einmal. Oder ich kann die 'passende Stelle' in jeweils eine eigene Prozedur auslagern. Das wären dann 9 - 12 Zuweisungsproceduren, gleichviel, wie einzelne Eventhandler nötig wären.
Einzig bei den 'Kanonieren' (die das Event abfeuern) wäre was einzusparen.

Inzwischen habe ich deinen neuen Beitrag mitbekommen, Dejan Vu.
Zitat:
'Case' (oder hier: if/else-Schlangen) sind zwar 'böse', aber in Fabrikmethoden durchaus erlaubt. Denn es ist ja nun kein Mehrwert ggü dem if/else bzw. 'case' (geht hier leider nicht), eine 1:1 Abbildung in eine Liste (oder Dictionary) zu stopfen.
Und damit sprichst du eigentlich genau das an, was mir kürzlich in den Sinn gekommen ist: meine Attributklassen befinden sich alle in einer Objectliste. Es reicht also, diese zu durchlaufen und in einer Prozedur auf die Klasseninstanz zu prüfen.

Zitat:
(Gerade fällt mir auf, dass die Basis-Klasse keinen Destruktor hat ... ts ts ts)
UUps!! - Du meinst sicher meine...

Gruss
Delbor
Roger
Man muss und kann nicht alles wissen - man muss nur wissen, wo es steht.
Frei nach Albert Einstein
http://roase.ch
  Mit Zitat antworten Zitat
Benutzerbild von Sir Rufo
Sir Rufo

Registriert seit: 5. Jan 2005
Ort: Stadthagen
9.454 Beiträge
 
Delphi 10 Seattle Enterprise
 
#9

AW: Klasseninstanz zur Laufzeit bestimmen

  Alt 2. Aug 2015, 14:48
Nein, mein TObjectHandler hat keinen, obwohl dort das Dictionary aufgeräumt werden muss.
Kaum macht man's richtig - schon funktioniert's
Zertifikat: Sir Rufo (Fingerprint: ‎ea 0a 4c 14 0d b6 3a a4 c1 c5 b9 dc 90 9d f0 e9 de 13 da 60)
  Mit Zitat antworten Zitat
Antwort Antwort


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 20:48 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-2025 by Thomas Breitkreuz