【发布时间】:2015-08-11 05:40:32
【问题描述】:
我正在尝试找出对一些遗留代码使用依赖注入的最佳方法,这将需要很长时间才能重构并且必须逐步完成。大多数旧类使用“父”属性来确定各种事物,父属性通常通过构造函数参数传入,如下所示:
constructor TParentObject.Create;
begin
FChildObject := TChildObject.Create(Self);
end;
constructor TChildObject.Create(AParent: TParentObject)
begin
FParent := AParent;
end;
这是我们遗留代码库的典型特征。但是,当转向接口和构造函数注入时,Spring4D 框架在创建 Child 对象时不知道 Parent。所以它只会得到一个新的父母,而不是现有的父母。当然,我可以创建一个属性 getter/setter,但这将表明该类的“可选”属性实际上是一个强制属性。更多解释见下面代码:
unit uInterfaces;
interface
uses
Spring.Collections;
type
IChildObject = interface;
IParentObject = interface
['{8EA8F9A2-E627-4546-8008-0A77DA2B16F1}']
function GetSomethingRequiredByChild: string;
procedure SetSomethingRequiredByChild(const Value: string);
property SomethingRequiredByChild: string read GetSomethingRequiredByChild write SetSomethingRequiredByChild;
function GetChild: IChildObject;
property Child: IChildObject read GetChild;
end;
// This introduces a property getter/setter
// However it also implies that Parent can be NIL which it cannot
IChildObject = interface
['{ECCA09A6-4A52-4BE4-A72E-2801160A9086}']
function GetParent: IParentObject;
procedure SetParent(const Value: IParentObject);
property Parent: IParentObject read GetParent write SetParent;
end;
TParentObject = class(TInterfacedObject, IParentObject)
private
FChild: IChildObject;
FSomethingRequiredByChild: string;
function GetChild: IChildObject;
function GetSomethingRequiredByChild: string;
procedure SetSomethingRequiredByChild(const Value: string);
public
constructor Create;
end;
TChildObject = class(TInterfacedObject, IChildObject)
private
FParent: IParentObject;
function GetParent: IParentObject;
procedure SetParent(const Value: IParentObject);
public
// This requries a Parent object, but how does the Spring4D resolve the correct parent?
constructor Create(const AParent: IParentObject);
end;
implementation
uses
Spring.Services;
{ TParentObject }
constructor TParentObject.Create;
begin
// Here is the old way...
FChild := TChildObject.Create(Self); // Old way of doing it
// This is the Service Locator way...
FChild := ServiceLocator.GetService<IChildObject>;
// I would prefer that the Parent is assigned somehow by the Service Locator
// IS THIS POSSIBLE - or am I dreaming?
FChild.Parent := Self;
end;
function TParentObject.GetChild: IChildObject;
begin
Result := FChild;
end;
function TParentObject.GetSomethingRequiredByChild: string;
begin
Result := FSomethingRequiredByChild;
end;
procedure TParentObject.SetSomethingRequiredByChild(const Value: string);
begin
FSomethingRequiredByChild := Value;
end;
{ TChildObject }
constructor TChildObject.Create(const AParent: IParentObject);
begin
FParent := AParent;
end;
function TChildObject.GetParent: IParentObject;
begin
Result := FParent;
end;
procedure TChildObject.SetParent(const Value: IParentObject);
begin
FParent := Value;
end;
end.
也许有一些我不知道的方法可用于使用 DI 框架设置父对象?
我希望这个问题很清楚我想要达到的目标。我很乐意在必要时提供更多描述/代码示例。
【问题讨论】:
-
看看实际“创建”子对象的代码会很有趣。我闻到服务定位器的味道。
-
哈哈 Stefan 你确实是对的,这就是我打算使用的,但想知道是否有替代方案?我现在将发布代码。
-
我的问题是:为什么你觉得这比直接在 TParentObject 中调用 TChildObject 的构造函数更好?我想真正的代码有点复杂,但仍然:如果你有父/子关系,这些类可能无论如何都知道彼此。如果不是这种情况,我建议使用工厂模式。将发布一些代码。
-
我正在尝试解耦许多旧的“意大利面条”代码单元,并使它们成为具有独立单元接口的小型、干净的类,以便我们可以为所有类创建单元测试。我们更喜欢尽可能多地移除紧密耦合的依赖,让框架通过注入来处理。它非常适合我们正在编写的新代码,但是迁移遗留代码更具挑战性:-)
-
如果你想去掉这个父子耦合,你可以这样做吗?没有父母,孩子还能存在吗?还是父母需要比孩子长寿?
标签: delphi dependency-injection spring4d