Question

One of the "Service Locator" pattern drawbacks is that a caller can be misleaded about dependencies of a callee.

Ok, but what if I put dependencies as generic parameters at a class level:

class Node<T> where T : ISomeInterface, new()
{
  ISomeInterface obj
  public Node()
  {
     obj = new T();
  }
}

I have found a couple of opinions here. But I want a discussion to be continued.

The most significant counterargument is that dependency injecting using generics makes late binding unavailable. But who cares in most cases? What if my app does not need this feature?

I want to find some solid counterarguments.

p.s. new() constraint is not necessary, as you understand.

Was it helpful?

Solution

The linked article is a bit misleading, in my opinion. Yes, using Inversion of Control containers makes some errors appear at runtime rather than compile time. And in general, it makes the process of writing and maintaining your code more fragile. This applies to Service Locators or really any other IoC container in my experience. This does not make them anti-patterns.

The key thing is that if you don't need that sort of plugin behavior, then don't use it. All design decisions are a trade off, and in IoC's case, that late binding (and ease of testing) is what you get and runtime errors rather than compile time (and decreased readability/debug-ability) is what you pay.

Indeed, your default approach should just be making plain old objects that take parameters in their constructor. Once that's insufficient, then start worrying about fancy tricks.

OTHER TIPS

I would say that your solution is actually worse than the original.

  1. You're limiting yourself to types that have default constructor. What if you want to use a type that takes some configuration in its constructor?
  2. If you have a dependency that has a dependency that has a dependency, you end up with horrible types like Node<Foo<Bar<Baz>>>. This doesn't make much sense, especially since none of the members of the type actually depend on the type parameters.
  3. You need to specify the concrete type of dependency at compile time. This makes your code much less flexible and you can't for example switch the dependency just by editing a configuration file (which can be useful).
  4. How is new Node<Foo>() any better than new Node(new Foo())?
Licensed under: CC-BY-SA with attribution
scroll top