0

In the spring4d demos, ServiceLocator.GetService<MyType>('Name') is used to resolve the types. But why not use GlobalContainer.Resolve<MyType>('Name')? I don't see any advantage in this approach...

Florian Koch
  • 1,372
  • 1
  • 30
  • 49
  • [Some](http://blog.ploeh.dk/2010/02/03/ServiceLocatorisanAnti-Pattern/) consider [service locator](http://stackoverflow.com/questions/22795459/is-servicelocator-anti-pattern) an anti pattern. I'd consider alternatives to both of those. – Sam Holder Apr 13 '15 at 15:11
  • Since both use global variables they aren't cool, yeah. But do you have a suggestion for an alternative? – Florian Koch Apr 13 '15 at 15:21
  • 2
    I think you can just make sure that you only use the container in the [CompositionRoot](http://stackoverflow.com/questions/6277771/what-is-a-composition-root-in-the-context-of-dependency-injection) of your application and then either will be the same, as, so long as the object graph is constructed completely in the composition root (and the container is not referenced outside of this location) then the service locator is functionally the same as dependency injection. – Sam Holder Apr 13 '15 at 15:25
  • but what is the difference? why use the service locator when i can take the container? – Florian Koch Apr 13 '15 at 15:49
  • 1
    I recommend using GlobalContainer.Resolve, and ignore ServiceLocator altogether. I also recommend make that call in the composition root of your application. In Delphi, this is generally in the DPR file. – Nick Hodges Apr 14 '15 at 12:52

1 Answers1

1

There is one use case, where I use ServiceLocator: when coding to make legacy code projects unit-testable...

There is an old project, where in mulitiple places, there are constructor calls of an object, which I write tests for (new and changed methods only, in classes, where injection is not possible, e.g. when a Form is created and destroyed in a button event).

In unit-tests, spring4d is helpful to instantiate the class-under-test:

I can use the GlobalContainer in the dpr for the production project and a special (test-only) TContainer-object which is constructed in Testfixture.Setup and destroyed in Testfixture.TearDown... I also re-initialize the global Service-Locator to use my Test-Container (Reason: I have bad experiences to use GlobalContainer in Test, you cannot un-register a type from GlobalContainer in Testfixture.TearDown).

So now, I got a big method in the dpr, where I register all types to GlobalContainer in the production-code project. In the Setup-Method of my test-fixture-class, I register all types needed for the test to my Testing-Container. And in the Methods, that I changed to make them unit-testable, I construct the classes-under-test with ServiceLocator, where formerly constructor-calls where used.

For me, it is the only way to make such a legacy-code project unit-testable... But my strategic goal is to replace most of this code (part-by-part, including the re-initialized ServiceLocators) one day. It is just not possible to replace it now (too much costs, too much risk...).

Markus
  • 357
  • 2
  • 13
  • oh ok, so basically your only reason to use service locator is the possibilty to change the underlaying container - sounds reasonable – Florian Koch May 01 '15 at 13:04
  • Not the only reason... [Inject] attribute is just not possible... the lifecycle of some objects is just inside a method... how to do this with [Inject] ? – Markus May 04 '15 at 08:18