2012-07-03 10 views
7

Ich beginne gerade mit dem Delphi Spring Framework und frage mich, ob die aktuelle Version des DI-Containers es irgendwie erlaubt, die Konstruktion an eine Factory-Methode zu delegieren, ohne einen Implementierungstyp anzugeben?Delphi Spring DI: Ist es möglich, Interface Instanziierung ohne einen Implementierungstyp zu delegieren?

z. Ähnliches:

Wie Sie sehen können, ist mein spezifischer Anwendungsfall die Instanziierung von COM-Objekten. In diesem Fall ist die Klasse, die die Schnittstelle implementiert, an der ich interessiert bin, nicht Teil meiner Anwendung, aber ich bin immer noch in der Lage, Instanzen durch Aufruf von CreateComObject/CoCreateInstance zu erstellen. Es scheint jedoch, dass ich Pech habe, da Registrierungen im Container immer an eine tatsächliche Implementierungsklasse gebunden zu sein scheinen.

Vorausgesetzt, dies ist im Moment nicht möglich, wie würden Sie die Experten da draußen ansprechen? Würden Sie eine Wrapper-Klasse oder Dummy-Klasse erstellen oder würden Sie einfach COM-Objekte aus dem DI-Container heraushalten und sie einfach über CreateComObject instanziieren?

Antwort

8

Leider erlaubt das aktuelle Design des Feder-DI-Containers das nicht. Es nimmt intern an, dass jeder Diensttyp (normalerweise Schnittstelle, kann aber auch eine Klasse sein) durch einen Komponententyp (eine Klasse) implementiert wird. Also TObject an mehreren Stellen, wo wir IInterface in diesem Fall benötigen würden. Wie der Delegat, den Sie an die DelegateTo-Methode übergeben, gibt der Komponententyp (oder TObject im nicht allgemeinen Fall) und nicht den Diensttyp zurück.

Das liegt auch daran, dass Sie einen Komponententyp mit mehreren Schnittstellenimplementierungen in nur einem fließenden Interface-Aufruf registrieren können. Wie:

GlobalContainer 
    .RegisterType<TMyObject> 
    .Implements<IMyInterface> 
    .Implements<IMyOtherInterface>; 

Der Behälter überprüft nun, ob TMyObject-IMyInterface und IMyOtherInterface kompatibel ist. Beim Aufruf von Resolve verwendet der Service Resolver GetInterface für die Instanz, um die angeforderte Schnittstellenreferenz zu erhalten. Alles, was darüber hinausgeht, wird für eine Objektreferenz ausgeführt.

Da ich einige Pläne für den DI-Container habe, die keine Abhängigkeit von einer implementierenden Klasse bei der Registrierung von Schnittstellen benötigen, wird dieses Problem in Zukunft, aber nicht in der Zukunft behoben.

Update (08.11.2012):

Da R522 ist es möglich, Schnittstellentypen in der folgenden Art und Weise zu registrieren:

GlobalContainer 
    .RegisterType<ISomeObject> 
    .DelegateTo(
    function: ISomeObject 
    begin 
     Result := CreateComObject(CLASS_SomeObject) as ISomeObject; 
    end) 
    .AsSingletonPerThread; 

In diesem Beispiel wird es ISomeObject als Dienst und jede Schnittstelle registrieren mit einer GUID, von der er erbt.

Zusätzlich können Sie andere Schnittstellen hinzufügen, indem Sie Implements<T> aufrufen, aber im Gegensatz zu Klassen wird es keine Validierung zur Registrierungszeit geben, wenn die konstruierte Instanz tatsächlich diese Schnittstelle unterstützt, da dies einfach nicht möglich ist. Derzeit erhalten Sie nil beim Aufruf Resolve<T> mit einem nicht unterstützten Service-Typ. Es kann in Zukunft eine Ausnahme auslösen.

+3

Danke für das Update! Das ist hervorragend! :) –

1

Sieht nicht so aus, wie die Architektur des Spring Frameworks es derzeit unterstützt, aber es ist sicherlich machbar. Es war suggested in der Spring4D-Support-Gruppe und es besteht Interesse an der Idee.

Es gibt eine generische TFactory Klasse in Spring.DesignPatterns, die in der Verpackung CreateComObject/COCreateInstance verwendet werden kann.