![]() |
ClassFactory ähnlich wie Spring Framework, Hilfe gesucht!
Hallo Zusammen!
Ich möchte in einer GlobalenListe einen Bezug vom Interface zu Klasse herstellen.
Delphi-Quellcode:
Um dann an einer anderen Stelle:
Unit MyFooImp;
Interface Implementation Uses MyContainer,MyInterfaces; // Defionition von IFoo Type TFoo = class(TInheritedObject,iFoo); Procedure bla; // bla bla end; Initialization GlobalContainer.Registerclass<IFoo,TFoo>; // Dictionary end.
Delphi-Quellcode:
Bei der Formfactory war das irgentwie kein Problem mit der Class of TForm, aber hier bekomme ich es einfach nicht hin, aus GlobalContainer.GetClass<IFoo> logisch TFoo.Create zu machen.
Procedure DoFoo;
var Foo : IFoo; begin Foo := GlobalContainer.GetClass<IFoo>; // Result unterschiedlich IFoo & TObject Foo.Bla; end; Hat jemand ne Idee? |
AW: ClassFactory ähnlich wie Spring Framework, Hilfe gesucht!
Dann wäre doch DSPING etwas für dich, bzw. kannst du dort nachschauen, wie das dort gelöst wird.
|
AW: ClassFactory ähnlich wie Spring Framework, Hilfe gesucht!
Zitat:
|
AW: ClassFactory ähnlich wie Spring Framework, Hilfe gesucht!
|
AW: ClassFactory ähnlich wie Spring Framework, Hilfe gesucht!
Damit geht das
Delphi-Quellcode:
unit Container;
interface uses System.Generics.Collections; type GlobalContainer = class private class var _ClassDict : TDictionary<TGUID, TClass>; protected class constructor Create; class destructor Destroy; public class procedure RegisterClass<TInterface : IInterface; TRegClass : class>; class function GetClass<T : IInterface> : T; end; implementation uses System.SysUtils, System.TypInfo; { GlobalContainer } class constructor GlobalContainer.Create; begin _ClassDict := TDictionary<TGUID, TClass>.Create; end; class destructor GlobalContainer.Destroy; begin _ClassDict.Free; end; 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; class procedure GlobalContainer.RegisterClass<TInterface, TRegClass>; var LGUID : TGUID; begin LGUID := GetTypeData( TypeInfo( TInterface ) ).Guid; _ClassDict.AddOrSetValue( LGUID, TRegClass ); end; end. |
AW: ClassFactory ähnlich wie Spring Framework, Hilfe gesucht!
Wenn man auch noch das hier
Delphi-Quellcode:
abgetütet haben will, dann so
type
IFoo = interface ['{4C53C006-737E-4F3C-A424-D5A34335EC0C}'] procedure Bar; end; TFoo = class( TInterfacedObject, IFoo ) private procedure Bar; end; TAnotherFoo = class( TFoo ) private procedure Bar; end; { TFoo } procedure TFoo.Bar; begin Writeln( Self.ClassName + '.Bar' ); end; { TAnotherFoo } procedure TAnotherFoo.Bar; begin Writeln( Self.ClassName + '.Bar' ); end; procedure Test; var LFoo : IFoo; begin GlobalContainer.RegisterClass<IFoo, TFoo>; GlobalContainer.RegisterClass<IFoo, TAnotherFoo>( 'Another' ); LFoo := GlobalContainer.GetClass<IFoo>; LFoo.Bar; // -> TFoo.Bar LFoo := GlobalContainer.GetClass<IFoo>( 'Another' ); LFoo.Bar; // -> TAnotherFoo.Bar end;
Delphi-Quellcode:
unit Container;
interface uses System.SysUtils, System.Generics.Collections; type EContainerException = class( Exception ); GlobalContainer = class private class var _ClassDict : TDictionary<string, TClass>; protected class constructor Create; class destructor Destroy; public class procedure RegisterClass<TInterface : IInterface; TRegClass : class>( const Name : string = '' ); class function GetClass<T : IInterface>( const Name : string = '' ) : T; end; implementation uses System.TypInfo; { GlobalContainer } class constructor GlobalContainer.Create; begin _ClassDict := TDictionary<string, TClass>.Create; end; class destructor GlobalContainer.Destroy; begin _ClassDict.Free; end; class function GlobalContainer.GetClass<T>( const Name : string ) : T; var LGUID : TGUID; LKey : string; LClass : TClass; LObj : TObject; begin LGUID := GetTypeData( TypeInfo( T ) ).Guid; LKey := LGUID.ToString + Name.ToUpper; if _ClassDict.ContainsKey( LKey ) then begin LClass := _ClassDict.Items[LKey]; LObj := LClass.Create; Supports( LObj, LGUID, Result ); end else raise EContainerException.CreateFmt( 'Keine Klasse zum Interface%s(%s) gefunden', [LGUID.ToString, Name] ); end; class procedure GlobalContainer.RegisterClass<TInterface, TRegClass>( const Name : string ); var LGUID : TGUID; LKey : string; begin LGUID := GetTypeData( TypeInfo( TInterface ) ).Guid; LKey := LGUID.ToString + Name.ToUpper; _ClassDict.AddOrSetValue( LKey, TRegClass ); end; end. |
AW: ClassFactory ähnlich wie Spring Framework, Hilfe gesucht!
Zitat:
Musste noch meinen GlobalContainer umbauen, das war auch ein Interface und da wollte Generics nicht. Mavarik |
AW: ClassFactory ähnlich wie Spring Framework, Hilfe gesucht!
Zitat:
Es fehlt allerdings bei der Registrierung die Prüfung, ob die Klasse das Interface unterstützt. Aber war auch nur auf die Schnelle ;) |
AW: ClassFactory ähnlich wie Spring Framework, Hilfe gesucht!
Zitat:
Delphi-Quellcode:
Mavarik
if _ClassDict.ContainsKey( LGUID ) then
begin LClass := _ClassDict.Items[LGUID]; LObj := LClass.Create; if not(Supports( LObj, LGUID, Result )) then raise EContainerException.CreateFmt( 'Keine Klasse zum Interface%s(%s) gefunden', [LGUID.ToString, Name] ); end; |
AW: ClassFactory ähnlich wie Spring Framework, Hilfe gesucht!
Zitat:
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
Delphi-Quellcode:
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
Create(AOwner: TComponent)
Delphi-Quellcode:
ziemlich böse Folgen haben kann.
T.Create
Aktueller Source von Spring4d liegt übrigens hier: ![]() Mein Vorschlag wäre übrigens, nicht Interface/Klasse als Kombination zu registrieren, sondern Interface/Factory. Somit würde aus deinem Dictionary ein
Delphi-Quellcode:
.
TDictionary<string, TFunc<IInterface>>
Die RegisterClass Methode würd ich dann so schreiben (nicht Compiler checked):
Delphi-Quellcode:
Das hat nun den Vorteil, dass du auch eine
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;
Delphi-Quellcode:
schreiben kannst und nicht nur auf Zuordnung von Interface zu Klasse beschränkt bist.
RegisterClass<IMyIntf>(function: IMyIntf begin Result := GetMyIntfFromSomewhere() end)
|
Alle Zeitangaben in WEZ +1. Es ist jetzt 21:53 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