Delphi 依赖注入:框架与委托构造函数
当您可以简单地使用以下模式时,为什么还要使用依赖注入框架?
unit uSomeServiceIntf;
interface
type
ISomeService = interface
procedure SomeMethod;
end;
var
CreateSomeService: function: ISomeService;
implementation
end.
unit uSomeServiceImpl;
interface
type
TSomeService = class(TInterfacedObject, ISomeService)
procedure DoSomething;
end;
function CreateSomeService: ISomeService;
implementation
function CreateSomeService: ISomeService;
begin
Result := TSomeService.Create;
end;
procedure TSomeService.DoSomeThing;
begin
...
end;
end.
unit uInitializeSystem;
interface
procedure Initialze;
implementation
uses
uSomeServiceIntf,
uSomeServiceImpl;
procedure Initialze;
begin
uSomeServiceIntf.CreateSomeService := uSomeServiceImpl.CreateSomeService;
end;
end.
我试图掌握使用框架而不是这样做的好处,但到目前为止我只看到这种简单方法的好处:
1)参数化构造函数更容易实现。例如: 变量 CreateSomeOtherService:函数(aValue:字符串);
2) 更快(容器中无需查找)
3) 更简单
这就是我使用它的方式:
unit uBusiness;
interface
[...]
implementation
uses
uSomeServiceIntf;
[...]
procedure TMyBusinessClass.DoSomething;
var
someService: ISomeService;
begin
someService := CreateSomeService;
someService.SomeMethod;
end;
end.
您使用 DI 框架而不是这种方法的理由是什么?
使用 DI 框架会是什么样子?
据我所知,如果您使用 DI 框架,那么您将针对接口注册具体类,然后系统的使用者将请求给定框架的实现。 因此,将会有一个注册调用:
DIFramework.Register(ISomeInterface, TSomeInterface)
当您需要 ISomeInterface 实现时,您可以向 DI 框架询问它:
var
someInterface: ISomeInterface;
begin
someInteface := DIFrameWork.Get(ISomeInterface) as ISomeInterface;
现在显然,如果您确实需要传递参数来创建 ISomeInterface,则 DIFramework 的整个事情会变得更加复杂(但使用 DI 框架很简单)上述方法)。
Why would you use a Dependency Injection Framework when you can simple use the following pattern?
unit uSomeServiceIntf;
interface
type
ISomeService = interface
procedure SomeMethod;
end;
var
CreateSomeService: function: ISomeService;
implementation
end.
unit uSomeServiceImpl;
interface
type
TSomeService = class(TInterfacedObject, ISomeService)
procedure DoSomething;
end;
function CreateSomeService: ISomeService;
implementation
function CreateSomeService: ISomeService;
begin
Result := TSomeService.Create;
end;
procedure TSomeService.DoSomeThing;
begin
...
end;
end.
unit uInitializeSystem;
interface
procedure Initialze;
implementation
uses
uSomeServiceIntf,
uSomeServiceImpl;
procedure Initialze;
begin
uSomeServiceIntf.CreateSomeService := uSomeServiceImpl.CreateSomeService;
end;
end.
I am trying to grasp the benefits of using a framework instead of doing this but so far I only see the benefits of this simple approach:
1) Parameterized constructors are easier to implement. E.g.:
var
CreateSomeOtherService: function(aValue: string);
2) Faster (no lookups necessary in a container)
3) Simplier
This is how I would use it:
unit uBusiness;
interface
[...]
implementation
uses
uSomeServiceIntf;
[...]
procedure TMyBusinessClass.DoSomething;
var
someService: ISomeService;
begin
someService := CreateSomeService;
someService.SomeMethod;
end;
end.
What would be your reasoning to use a DI framework instead of this approach?
How this would look like using a DI framework?
As far as I know if you would use a DI framework than you would register the concrete class against the interface and then consumers of the system would ask an implementation for the given framework.
So there would be a registering call:
DIFramework.Register(ISomeInterface, TSomeInterface)
and when you need an ISomeInterface implementation you can ask the DI framework for it:
var
someInterface: ISomeInterface;
begin
someInteface := DIFrameWork.Get(ISomeInterface) as ISomeInterface;
Now obviously if you do need to pass parameters to create an ISomeInterface the whole thing gets more complicated with the DIFramework (but simple with the approach described above).
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
在您的情况下,您必须在设计时提前知道工厂函数 ptr (
var CreateSomeService
) 的名称。当然,接口和函数 ptr 在同一个 Delphi 单元文件中耦合在一起,但这只是 Delphi 的遗留物,全局 var 不是线程安全的,也不受访问保护。如果您在运行时获得了一个接口,作为某些函数或从配置文件中读取的结果,您不知道要调用哪个工厂函数来获取实现者的实际实例,该怎么办?
DIFrameWork.Get(ISomeInterface) as ISomeInterface
对您隐藏了工厂函数,因此您只需要接口,而不需要接口和工厂函数。如果您想隐藏工厂函数,那么您还必须隐藏参数。 (最终会得到类似于 DI 框架的东西)。In your case you have to know the name of the factory function ptr (
var CreateSomeService
) in advance, at design-time. Sure, the interface and the function ptr are coupled together in the same Delphi unit file, but that's just a Delphi relic, global var is not thread safe and not access-protected.And what if you got an interface at runtime, as a result of some function or a read from a config file - you don't know what factory function to call to get the actual instance of an implementor.
DIFrameWork.Get(ISomeInterface) as ISomeInterface
hides the factory function from you so you only need the interface, not both the interface and the factory function. If you would try to hide the factory function then you'd also have to hide the parameters. (and would end up with something much like that DI framework).当您需要其他人制作的接口并指示 IoC 容器创建时,DI 工厂会有所帮助,有时外部库会向您隐藏实现。如果您是创建接口以及使用接口的人,您应该查看基于项目范围为您创建对象的工厂模式,并考虑将其范围限定为单例或对所有项都相同一笔“交易”。
您可以为单例生成一个静态类,例如“设置”,涉及涉及多个对象状态的事务的数据库会话怎么样……那么就不那么有趣了。您应该为“正确的问题”考虑正确的解决方案。
the DI factory helps when you need an interface that someone else made and instructed the IoC container to create, sometimes an external library will hide the implementation from you. If you are the one creating the interfaces as well as using the interfaces you should look at the factory pattern creating the object for you based on the scope of the item, with the consideration of it being scoped as a singleton or the same for all in a "transaction".
You could generate a static class for singletons like "settings" what about the database session involved with a transaction that is touching the state of several objects... not so funny then. You should consider the right solution for the "right problem".