我试图找出对一些遗留代码使用依赖注入的最佳方法,这将需要很长时间来重构并且必须逐步完成。大多数旧类使用“父”属性来确定各种事物,并且父属性通常通过构造函数参数传入,如下所示:
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 框架设置父对象?
我希望这个问题很清楚我想要达到的目标。我很乐意在必要时提供更多描述/代码示例。