Search code examples
delphispring4d

spring4d resolve a local constructed class


Let's say, I have the following code:

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.

The method ButtonEvent is called by a delphi form button click event.

Now my question: Is there a better way to instantiate the class TMyClass2? Injection into the class TMyClass1 is not possible in my case, the lifetime of TMyClass2 instance is only inside ButtonEvent. Next call to ButtonEvent should use a different instance...

AFAIK, method parameter injection or local variable injection is not possible in Spring4D, is it?


Solution

  • If you want to avoid the dreaded service locator pattern which does not solve the problem that DI solves but just shifts it (or in many cases even makes things worse because you have pseudo decoupled code which still has dependencies that you only experience once you run the code and figure out that you have to register some type in order to make the service locator to return the correct thing).

    Method parameter injection or local variable injection? How on earth would that be possible. It would require some interception of the call in order for the container to inject something into the registers/stack.

    While interception is possible for certain methods (virtual ones) that still requires the called instance to be set up for that. And if you do that you could have injected your dependency in the first place.

    If you don't place DI in your composition root you always have to use some kind of service locator inside the code from where you want to start the process of dependency injection.

    Think of DI and especially the use of a container as tool to achieve something specific: mostly decoupling your code for its various benefits. As I said the use of a service locator in such cases can cause more problems than it solves.

    However back to your example: this is the classic case for using a factory. You need to inject that into your TMyClass1. It then can call the factory in your method and retrieve the IMyInterface2. Depending on the Spring4D version you are using there are different ways the container can save you some work as it is able to construct the factory for you. But I suggest writing the factory yourself using the classic pattern. That way you get a feel for it. Later when you are more experienced and confident with its use and where to use the container can easily take over that part.