Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Delphi Dependency Injection: Framework vs Delegating Constructor

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).

like image 436
RM. Avatar asked May 10 '11 04:05

RM.


1 Answers

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).

like image 175
Boris B. Avatar answered Oct 31 '22 19:10

Boris B.