spring4d 解析一个本地构造的class
spring4d resolve a local constructed class
比方说,我有以下代码:
interface
type
IMyInterface1 = interface // GUID
procedure ButtonEvent(Sender: TObject);
end;
IMyInterface2 = interface // GUID
procedure DoSomething;
end;
TMyClass1 = class(TInterfacedObject, IMyInterface1)
public
procedure ButtonEvent(Sender: TObject);
end;
TMyClass2 = class(TInterfacedObject, IMyInterface2)
public
procedure DoSomething;
end;
// ...
implementation
procedure TMyClass1.ButtonEvent(Sender: TObject);
var
aIntf2: TMyInterface2;
begin
// Pseudo code:
// aIntf2 := ServiceLocator.GetService<IMyInterface2>;
try
aIntf2.DoSomething;
finally
aIntf2 := nil; // will free the instance...
end;
end;
initialization
// Pseudo code:
// GlobalContainer register IMyInterface1 / TMyClass1
// GlobalContainer register IMyInterface2 / TMyClass2
// GlobalContainer.Build
end.
ButtonEvent 方法由 delphi 表单按钮单击事件调用。
现在我的问题是:
有没有更好的方法来实例化 class TMyClass2?
在我的例子中,注入 class TMyClass1 是不可能的,TMyClass2 实例的生命周期仅在 ButtonEvent 内。
下次调用 ButtonEvent 应该使用不同的实例...
据我所知,方法参数注入或局部变量注入在 Spring4D 中是不可能的,是吗?
如果你想避免可怕的服务定位器模式,它不能解决 DI 解决的问题,而只是转移它(或者在许多情况下甚至会使事情变得更糟,因为你有伪解耦代码,它仍然具有你只体验一下 运行 代码并弄清楚必须注册某种类型才能使服务定位器成为 return 正确的东西)。
方法参数注入还是局部变量注入?这怎么可能。它需要对调用进行一些拦截,以便容器将某些内容注入 registers/stack.
虽然某些方法(虚拟方法)可以进行拦截,但仍需要为此设置被调用实例。如果你这样做,你可以在第一时间注入你的依赖。
如果您不将 DI 放在您的组合根中,您总是必须在代码中使用某种服务定位器,从您想要开始依赖注入过程的地方开始。
考虑 DI,尤其是使用容器作为实现特定目标的工具:主要是为了获得各种好处而解耦代码。正如我所说,在这种情况下使用服务定位器可能会导致比它解决的问题更多的问题。
然而回到你的例子:这是使用工厂的经典案例。您需要将其注入您的 TMyClass1。然后它可以在您的方法中调用工厂并检索 IMyInterface2。根据您使用的 Spring4D 版本,容器可以通过不同的方式为您节省一些工作,因为它能够为您构建工厂。但我建议使用经典模式自己编写工厂。这样你就能感受到它。稍后当您对它的使用更有经验和信心时,可以轻松地接管容器的使用位置。
比方说,我有以下代码:
interface
type
IMyInterface1 = interface // GUID
procedure ButtonEvent(Sender: TObject);
end;
IMyInterface2 = interface // GUID
procedure DoSomething;
end;
TMyClass1 = class(TInterfacedObject, IMyInterface1)
public
procedure ButtonEvent(Sender: TObject);
end;
TMyClass2 = class(TInterfacedObject, IMyInterface2)
public
procedure DoSomething;
end;
// ...
implementation
procedure TMyClass1.ButtonEvent(Sender: TObject);
var
aIntf2: TMyInterface2;
begin
// Pseudo code:
// aIntf2 := ServiceLocator.GetService<IMyInterface2>;
try
aIntf2.DoSomething;
finally
aIntf2 := nil; // will free the instance...
end;
end;
initialization
// Pseudo code:
// GlobalContainer register IMyInterface1 / TMyClass1
// GlobalContainer register IMyInterface2 / TMyClass2
// GlobalContainer.Build
end.
ButtonEvent 方法由 delphi 表单按钮单击事件调用。
现在我的问题是: 有没有更好的方法来实例化 class TMyClass2? 在我的例子中,注入 class TMyClass1 是不可能的,TMyClass2 实例的生命周期仅在 ButtonEvent 内。 下次调用 ButtonEvent 应该使用不同的实例...
据我所知,方法参数注入或局部变量注入在 Spring4D 中是不可能的,是吗?
如果你想避免可怕的服务定位器模式,它不能解决 DI 解决的问题,而只是转移它(或者在许多情况下甚至会使事情变得更糟,因为你有伪解耦代码,它仍然具有你只体验一下 运行 代码并弄清楚必须注册某种类型才能使服务定位器成为 return 正确的东西)。
方法参数注入还是局部变量注入?这怎么可能。它需要对调用进行一些拦截,以便容器将某些内容注入 registers/stack.
虽然某些方法(虚拟方法)可以进行拦截,但仍需要为此设置被调用实例。如果你这样做,你可以在第一时间注入你的依赖。
如果您不将 DI 放在您的组合根中,您总是必须在代码中使用某种服务定位器,从您想要开始依赖注入过程的地方开始。
考虑 DI,尤其是使用容器作为实现特定目标的工具:主要是为了获得各种好处而解耦代码。正如我所说,在这种情况下使用服务定位器可能会导致比它解决的问题更多的问题。
然而回到你的例子:这是使用工厂的经典案例。您需要将其注入您的 TMyClass1。然后它可以在您的方法中调用工厂并检索 IMyInterface2。根据您使用的 Spring4D 版本,容器可以通过不同的方式为您节省一些工作,因为它能够为您构建工厂。但我建议使用经典模式自己编写工厂。这样你就能感受到它。稍后当您对它的使用更有经验和信心时,可以轻松地接管容器的使用位置。