我遇到了从Spring4D框架容器解析的类型中正确对象实例化的问题。
我有一个班级:
type
TSurvey = class ( TInterfacedObject, ISurvey )
private
_id : Integer;
_organization : IOrganization;
function GetId () : Integer;
procedure SetId ( const value : Integer );
function GetOrganization () : IOrganization;
procedure SetOrganization ( const value : IOrganization);
public
property Id : Integer read GetId write SetId;
property Organization: IOrganization read GetOrganization write SetOrganization;
end;
...
initialization
GlobalContainer.RegisterType<TSurvey>.Implements<ISurvey>.InjectField ( '_organization' );
...
我使用GlobalContainer来实例化一个对象:
survey := GlobalContainer.Resolve<ISurvey>;
survey.Organization.Id := 5;
一切顺利,完美无缺。
现在我想为TSurvey创建一个后代类:
type
TFieldSurvey = class ( TSurvey )
...
end;
问题是如何纠正实例化TFieldSurvey类的对象?
如果我使用Create(),那么我会得到一个例外:
fieldSurvey := TFieldSurvey.Create ();
fieldSurvey.Organization.Id := 5 <- exception is here
我是否必须在TFieldSurvey构造函数中显式调用Organization字段的构造函数,还是有另一种方法?例如,使用GlobalContainer?
提前致谢。
答案 0 :(得分:4)
注入仅在通过Container创建对象时有效,而不是直接调用对象上的构造函数。因此,您需要使用TFieldSurvey
注册GlobalContainer
,然后致电Resolve
以获取您的对象。
寄存器:
GlobalContainer.RegisterType<TSurvey>.Implements<ISurvey>('SPRING_SURVEY').InjectField ( '_organization' );
GlobalContainer.RegisterType<TFieldSurvey>.Implements<ISurvey>('SPRING_FIELD_SURVEY').InjectField ( '_organization' );
然后获取一个实例:
GlobalContainer.Resolve<ISurvey>('SPRING_FIELD_SURVEY')
我添加了'SPRING_SURVEY'和'SPRING_FIELD_SURVEY'的名称,因为它们都实现了ISurvey
,这使您可以选择所需的类实例,否则最终会为该接口注册最后一个实现。如果TFieldSurvey
要实现自己的界面(例如IFieldSurvey
),您可以取消名称,然后在需要时将其转换回ISurvey
。
您也可以在_organization字段上使用[Inject]
属性,而不是使用.InjectField(在您的使用中添加Global.Container.Common
之后):
TSurvey = class ( TInterfacedObject, ISurvey )
private
_id : Integer;
[Inject]
_organization : IOrganization;
function GetId () : Integer;
procedure SetId ( const value : Integer );
function GetOrganization () : IOrganization;
procedure SetOrganization ( const value : IOrganization);
public
property Id : Integer read GetId write SetId;
property Organization: IOrganization read GetOrganization write SetOrganization;
end;
您的注册将是:
GlobalContainer.RegisterType<TSurvey>.Implements<ISurvey>('SPRING_SURVEY');
GlobalContainer.RegisterType<TFieldSurvey>.Implements<ISurvey>('SPRING_FIELD_SURVEY');
答案 1 :(得分:2)
您不应该以仅适用于DI容器的方式编写代码。
DI容器是一个工具,您应该避免(直接或间接)依赖它。
这意味着您应该避免使用字段注入,因为此类代码无法与pure DI一起使用 - 请改为使用构造函数或属性注入。
同样,从您发布的代码段中我可以闻到service locator anti pattern。
如果要创建调查,请使用调查工厂并将其注入您正在使用它的类中。 DI容器通常不用于创建值对象,而您的调查类(尽管不必要地具有接口)看起来像是一个。
在深入使用DI容器之前,我真的建议更多地了解DI的工作原理以及使用DI编写干净代码的技巧。然后才开始使用DI容器。反过来这样做只会导致错误,使代码最终难以维护。