Search code examples
delphispring4d

spring4D dependency injector with MVP


I'm using Spring4D's dependency injector in something organized as MVP, in my view I have the interface reference of my presenter and in the create method of the presenter I have the injection of the view's interface in the constructor, the view is registered as a singleton, however, when creating and resolving the Presenter, the view is created again and enters a loop, is it possible to do this with Spring4D?

procedure RegisterTypes(const Container: TContainer);
begin
  Container.RegisterType<TConexao>.asSingleton;
  Container.RegisterType<TConversorService>;
  Container.RegisterType<TfrmConversorView>.AsSingleton();
  Container.RegisterType<TConversorUseCase>;

  container.Build;
end;

My View(Form)

type
  TfrmConversorView = class(TForm, IConversorView)
    JvStatusBar1: TJvStatusBar;
    procedure FormShow(Sender: TObject);
    procedure FormCreate(Sender: TObject);
  private
    FService: IConversorService;
    { Private declarations }
  public
    { Public declarations }
  end;

...
procedure TfrmConversorView.FormCreate(Sender: TObject);
begin
  FService := GlobalContainer.Resolve<IConversorService>;
end;

My Presenter

Type
  TConversorService = Class(TInterfacedObject, IConversorService)
  Private
    FView: IConversorView;
    FUseCase: IConversorUseCase;

  Public

    Constructor Create(aView: IConversorView; aUseCase: IConversorUseCase);
  End;

implementation

{ TConversorService }

Constructor TConversorService.Create(aView: IConversorView; aUseCase: IConversorUseCase);
begin
  FView := aView;
  FUseCase := aUseCase;
end;

Tks.

I imagined that declaring as a singleton the existing instance of the object would be injected instead of creating a new one,


Solution

  • The issue is that you do service location which is a different Resolve chain from the one originally creating the view. That causes another creation of the TConversorService which is not marked as singleton. Design your code as if you were doing pure DI - tinkering with the DI container without proper design and then stuffing service location into your code always leads to issues.

    If you need a back reference to your IConversorService inside the view that gets injected into your IConversorService then the easiest way is to put a property onto your view which can be set inside of TConversorService.Create.