【问题标题】:Spring4d : Automatic factory with Owner : TComponent parameter?Spring4d:具有所有者的自动工厂:TComponent 参数?
【发布时间】:2015-12-15 04:05:05
【问题描述】:

使用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&lt;TMyDep&gt;依赖,只注册TMyDep类型。

可以传递类似的东西

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

无需在容器中注册?

【问题讨论】:

    标签: delphi dependency-injection spring4d


    【解决方案1】:

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

    但是,有一种方法可以摆脱使用 Spring.Container.Common 中不同的IFactory&lt;T,TResult&gt; 接口对 1-4 个参数进行手动工厂实现,这将在注册时由 DI 容器自动实现。

    所以你可以这样注册:

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

    像这样注册工厂,不需要你自己实现——容器会为你解决。

    这意味着,当您需要TMyObject 的实例时,您不再直接(从容器)请求它。相反,您确实请求IFactory&lt;TComponent, TMyObject&gt; 的实例,其中TComponentTMyObject 构造函数接受的唯一参数。

    作为使用来自另一个类TSomeClass 的构造函数注入的示例(其中TSomeClass 也是TComponent 的后代),它如下所示:

    constructor TSomeClass.Create(const AMyObjectFactory: IFactory<TComponent, TMyObject>);
    begin
      fMyObjectInstance := AMyObjectFactory(Self);
    end;
    

    至少对我来说,这让事情变得容易多了。

    【讨论】:

      【解决方案2】:

      如果我理解正确,你尽量避免这样的例行代码:

      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>;
      

      并像以前一样做。 Helper 类是这样定义的:

        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;
      

      【讨论】:

      • 谢谢两位,但我阅读答案的次数越多,我就越问自己是否应该注入生命周期管理(在这种情况下为所有权)?
      • @Ludo 我们无法在不知道您具体实施什么的情况下为您提供有关生命周期管理的建议。 Delphi 中有很多可能性:仅通过接口引用访问您的对象,如果 refcount 为零,则将其销毁,或者制作分层结构,其中所有者负责创建和销毁其组件,或者使其像在 VCL 中一样,其中表单拥有所有组件,或在某些地方进行手动内存管理。没有通用的解决方案。
      猜你喜欢
      • 1970-01-01
      • 2011-09-08
      • 2011-09-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-07-24
      • 1970-01-01
      相关资源
      最近更新 更多