Einzelnen Beitrag anzeigen

Benutzerbild von Stevie
Stevie

Registriert seit: 12. Aug 2003
Ort: Soest
4.027 Beiträge
 
Delphi 10.1 Berlin Enterprise
 
#10

AW: ClassFactory ähnlich wie Spring Framework, Hilfe gesucht!

  Alt 6. Feb 2014, 15:08
Damit geht das
Delphi-Quellcode:
class function GlobalContainer.GetClass<T> : T;
var
  LGUID : TGUID;
  LClass : TClass;
  LObj : TObject;
begin
  LGUID := GetTypeData( TypeInfo( T ) ).Guid;
  if _ClassDict.ContainsKey( LGUID ) then
  begin
    LClass := _ClassDict.Items[LGUID];
    LObj := LClass.Create;
    Supports( LObj, LGUID, Result );
  end;
end;
Leider geht das so nicht. Deshalb gibt es in Spring4d auch relativ komplexe Logik, um den "best matching" Konstruktor zu finden.
Es ist nämlich nicht immer richtig den Parameterlosen Standardkonstruktor aufzurufen, da er eigentlich versteckt wurde (z.B. bei TComponent)
Über deine Logik würde zwar der richtige Speicher allokiert aber niemals die ganzen Dinge aus dem Create(AOwner: TComponent) durchlaufen. Auch Spring4d ist nicht komplett wasserdicht, da die RTTI keine Möglichkeit bietet zu ermitteln, ob eine Methode überschrieben oder verdeckt wurde. Auch der constructor Constraint bei generics leidet unter dieser Macke, so dass ein T.Create ziemlich böse Folgen haben kann.

Aktueller Source von Spring4d liegt übrigens hier: https://bitbucket.org/sglienke/spring4d (das Google Code Repo wird nicht mehr aktualisiert)

Mein Vorschlag wäre übrigens, nicht Interface/Klasse als Kombination zu registrieren, sondern Interface/Factory.

Somit würde aus deinem Dictionary ein TDictionary<string, TFunc<IInterface>> .

Die RegisterClass Methode würd ich dann so schreiben (nicht Compiler checked):

Delphi-Quellcode:
class procedure GlobalContainer.RegisterClass<TInterface: IInterface, TRegClass: class, constructor>( const Name : string );
var
  LGUID : TGUID;
  LKey : string;
begin
  // hier aufpassen, kann auch keine guid haben, dann sollte man hier einen Fehler werfen, denn das resolven wird nicht ohne funktionieren
  // ebenfalls sollte man checken, ob die Klasse, das Interface überhaupt supported
  LGUID := GetTypeData( TypeInfo( TInterface ) ).Guid;
  LKey := LGUID.ToString + Name.ToUpper;
  _ClassDict.AddOrSetValue( LKey,
    function: IInterface
    var
      obj: TObject;
    begin
      // wie gesagt, hier aufpassen, kann sein, dass das den falschen Konstruktor aufruft, das fängt auch der constructor Contraint nicht korrekt ab
      obj := TRegClass.Create;
      // kein if notwendig, wenn oben geschaut wurde, ob das hier auch funktioniert
      Supports(obj, LGUID, Result);
    end);
end;
Das hat nun den Vorteil, dass du auch eine RegisterClass<IMyIntf>(function: IMyIntf begin Result := GetMyIntfFromSomewhere() end) schreiben kannst und nicht nur auf Zuordnung von Interface zu Klasse beschränkt bist.
Stefan
“Simplicity, carried to the extreme, becomes elegance.” Jon Franklin

Delphi Sorcery - DSharp - Spring4D - TestInsight

Geändert von Stevie ( 6. Feb 2014 um 15:20 Uhr)
  Mit Zitat antworten Zitat