Spring4d:带有Owner:TComponent参数的自动工厂?

3
使用 Spring4d,您可以这样注册自定义工厂。
aContainer.RegisterInstance<TFunc<string, TMyObject>>(function(aName : string):TMyObject
begin
    Result := TMyObject.Create(aName);
end);

以此方式,我相信对于每个继承自 TComponent 的依赖项,想要传递所有者的人只会这样做:

// Registrations 

aContainer.RegisterInstance<TFunc<TComponent, TMyObject>>(function(Owner : TComponent):TMyObject
begin
    Result := TMyObject.Create(Owner);
end);

// Then in code

constructor TMyClass.Create(aFctry : TFunc<TComponent, TMyObject>);
begin
    fObj := aFctry(Self);
end;

或者也可以这样做

aContainer.RegisterType<TMyObject, TMyObject>;

// In code

constructor TMyClass.Create(aObj : TMyObject);
begin
    fObj := aObj;
    InsertComponent(aObj);
end;

虽然这样做容易出错/需要添加代码才能传递所有者。有没有内置的方法可以获取一个以TComponent为参数的工厂,而不必事先在容器中注册它?
因为经常会使用
constructor MyObject.Create(aDep : TFunc<TMyDep>);

没有注册 TFunc<TMyDep> 依赖项,只注册了 TMyDep 类型。

是否可以传递类似以下内容:

constructor MyObject.Create(aDep : TFunc<TComponent, TMyDep>);

不需要在容器中注册它吗?
2个回答

3

据我所知,如果没有注册,这是不可能的。

但是,有一种方法可以通过使用Spring.Container.Common中的不同IFactory<T,TResult>接口来摆脱1-4个参数的手动工厂实现,当被注册时,DI容器将自动实现它们。

因此,您可以像这样注册它:

aContainer.RegisterType<TMyObject>;
aContainer.RegisterType<IFactory<TComponent, TMyObject>>.AsFactory;

以这种方式注册工厂,您不需要在您的代码中实现它 - 容器将为您解析它。
这意味着,每当您需要一个TMyObject实例时,您不再直接请求它(从容器)。相反,您需要请求一个IFactory<TComponent,TMyObject>实例,其中TComponentTMyObject构造函数接受的唯一参数。
作为使用来自另一个类TSomeClass的构造函数注入的示例(其中TSomeClass也是TComponent后代),它将如下所示:
constructor TSomeClass.Create(const AMyObjectFactory: IFactory<TComponent, TMyObject>);
begin
  fMyObjectInstance := AMyObjectFactory(Self);
end;

至少对我来说,这使事情变得更容易。


0

如果我理解正确,您试图避免像这样的例行代码:

aContainer.RegisterInstance<TFunc<TComponent, TMyFirstObject>>(function(Owner : TComponent):TMyFirstObject
begin
    Result := TMyFirstObject.Create(Owner);
end);

aContainer.RegisterInstance<TFunc<TComponent, TMySecondObject>>(function(Owner : TComponent):TMySecondObject
begin
    Result := TMySecondObject.Create(Owner);
end);

aContainer.RegisterInstance<TFunc<TComponent, TMyThirdObject>>(function(Owner : TComponent):TMyThirdObject
begin
    Result := TMyThirdObject.Create(Owner);
end);

好的,你可以用过程“RegisterComponentDescendant”定义辅助类,它会为你创建工厂,这样你编写的代码将像这样:

aContainer.RegisterComponentDescendant<TMyFirstObject>;
aContainer.RegisterComponentDescendant<TMySecondObject>;
aContainer.RegisterComponentDescendant<TMyThirdObject>;

然后做与之前相同的事情。帮助类的定义如下:

  TContainerHelper = class helper for TContainer
  public
    procedure RegisterComponentDescendant<TMyObject: TComponent>;
  end;

以及它的实现:

procedure TContainerHelper.RegisterComponentDescendant <TMyObject>;
begin
  self.RegisterInstance<TFunc<TComponent, TMyObject>>(
    function(Owner : TComponent):TMyObject
    begin
        Result := TMyObject.Create(Owner);
    end);
end;

谢谢你们两位,但是我越看回答,就越在问自己这种情况下是否应该注入生命周期管理(所有权)? - Ludovic C
@Ludo 如果不知道你具体实现的内容,我们就无法为你提供有关生命周期管理的建议。Delphi中有很多可能性:只通过接口引用访问对象,并在引用计数为零时销毁它,或创建和销毁其组件由所有者负责的分层结构,或像VCL中那样形成所有组件都归表单所有,或在某些地方进行手动内存管理。没有通用解决方案。 - Yuriy Afanasenkov

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接