我刚刚开始使用Delphi Spring框架,想知道当前版本的DI容器是否以某种方式允许在不指定实现类型的情况下将构造委托给工厂方法?
例如,类似于以下内容:
GlobalContainer
.RegisterFactory<ISomeObject>(
function: ISomeObject
begin
Result := CreateComObject(CLASS_SomeObject) as ISomeObject;
end)
.Implements<ISomeObject> // could probably be implied from the above
.AsSingletonPerThread;
如您所见,我的具体用例是 COM 对象的实例化。在这种情况下,实现我感兴趣的接口的类不是我应用程序的一部分,但我仍然能够通过调用 CreateComObject
/CoCreateInstance
来创建实例。但是,我似乎不走运,因为容器中的注册似乎总是绑定到实际的实现类。
假设目前这是不可能的,你们的专家将如何解决这个问题?您会创建一个包装类或虚拟类,还是只是将 COM 对象保留在 DI 容器之外并通过 CreateComObject
简单地实例化它们?
不幸的是,弹簧DI容器的当前设计不允许这样做。它在内部假定每个服务类型(通常是接口,但也可以是类)都由组件类型(类)实现。因此,在这种情况下,我们需要IInterface
的几个地方TObject
。与传递给 DelegateTo 方法的委托一样,该方法返回组件类型(在非泛型情况下为 TObject),而不是服务类型。
这也是因为您可以在一次流畅的接口调用中向多个接口实现注册一个组件类型。喜欢:
GlobalContainer
.RegisterType<TMyObject>
.Implements<IMyInterface>
.Implements<IMyOtherInterface>;
容器现在检查TMyObject
是否与IMyInterface
和IMyOtherInterface
兼容。调用Resolve
时,服务解析程序使用实例上的GetInterface
来获取请求的接口引用。超出该点的所有内容都是在对象引用上完成的。
由于我对 DI 容器有一些计划,在注册接口时不需要依赖于实现类,因此将来会解决这个问题,但不会很快解决。
更新(08.11.2012):
自 r522 起,可以通过以下方式注册接口类型:
GlobalContainer
.RegisterType<ISomeObject>
.DelegateTo(
function: ISomeObject
begin
Result := CreateComObject(CLASS_SomeObject) as ISomeObject;
end)
.AsSingletonPerThread;
在此示例中,它将ISomeObject
注册为服务以及具有它继承自的 GUID 的任何接口。
此外,您可以通过调用Implements<T>
添加其他接口,但与类不同的是,如果构造的实例实际上确实支持该接口,则在注册时不会进行验证,因为它根本不可能。目前,使用不受支持的服务类型调用Resolve<T>
时,您将获得nil
。将来可能会引发异常。
看起来 spring 框架的架构目前不支持它,但它肯定是可行的。在spring4d支持小组中已经提出了它,并且对这个想法很感兴趣。
Spring.DesignPatterns
中有一个泛型TFactory
类,可用于包装CreateComObject/COCreateInstance
。