3

I am somewhat new to Dependency Injection. I have set it up for some classes that pass in their dependencies as parameters in the constructor, but I have some constructors that take primitives like String or boolean. Obviously these need to be removed from the constructor if I am to use Dependency Injection for that class.

For a case like this, what is a "best" practice? Make the constructor just take the dependencies and provide a setter method for all of the primitives that the class requires?

skaz
  • 21,962
  • 20
  • 69
  • 98

3 Answers3

4

Obviously these need to be removed from the constructor if I am to use Dependency Injection for that class

No, not "Obviously". You can keep these parameters in as well as have the injected dependencies.

If the class requires these parameters for proper initialization, they need to be part of the constructor.

Oded
  • 489,969
  • 99
  • 883
  • 1,009
  • I KNEW obviously was going to bite me :) So if I do need this in the constructor, how do I go about using dependency injection? – skaz Nov 19 '11 at 20:04
  • @skaz - You simply pass in the dependencies. Or did you mean to ask about IoC containers? – Oded Nov 19 '11 at 20:05
  • Yes, maybe that is the term and I am unaware. I am attempting to inject the dependencies in by defining the object graph externally to the class. Please see my comment on Steven's answer for insight into what I am trying to do. Thanks for your help. – skaz Nov 19 '11 at 20:15
  • @skaz - I think I see what you mean now. You can always do property injection instead of constructor injection for your dependency injection. – Oded Nov 19 '11 at 20:20
  • If I have a `Resource` that encapsulates a `String` (which is the resource that the class represents), you think it makes sense to have a `setResource` method? I see how this is a workaround to the problem, but it feels a little weird that I wouldn't set the real essence of the instance at construction. Is this just the trade-off I have to make to use (what I now believe is called) Inversion of Control? Thanks again. – skaz Nov 19 '11 at 20:23
  • @skaz - This is an issue that is solved different ways by different IoC containers. There is also a matter of class design - different designs will work better for different usages of IoC. I know this is vague, but there are many variants and flavors. – Oded Nov 19 '11 at 20:27
3

My observation is that in most cases, classes that have a constructor that takes both dependencies and primitives, break the Single Responsibility Principle or at least result in a design that is less clean, which leads to container configurations that are more fragile and harder to understand.

In most (if not all) cases, those primitives are configuration values, such as connection strings, debug options, and such.

There are a few ways you can change your design to solve this:

  1. In the case you are breaking the SRP, extract the code into its own type. Take for instance this example where the NotifyCustomerHandler takes an string notificationServiceUrl, while that string should have been encapsulated into some sort of NotificationService.
  2. Another option is to extract the configuration values of a type into its own type. In the case of the NotifyCustomerHandler, it could take a dependency on an INotifyCustomerHandlerConfiguration. In the past I used to have a single IMyApplicationConfiguration interface, with all configuration values the application needed, but I came to the conclusion that this is a bad idea. This breaks the Interface Segregation Principle and your unit tests will start to suffer in terms of readability and maintainability.
  3. When you're not breaking the SRP and injecting a configuration object isn't practical (when you have a single primitive or getting too many configuration interfaces, or you just don't like that option), you can change these constructor arguments to public properties. This will allow you (with most containers) to register a delegate that will configure the instance after creation, in a way the compiler can verify this for you.
Community
  • 1
  • 1
Steven
  • 166,672
  • 24
  • 332
  • 435
  • Thanks for your well thought out answer. My constructor currently takes a String which contains JSON or XML. I could extract this into its own type, maybe `Resource` or something. But to get the `String` into this class to build the `Resource` it seems that I will suffer from the same problem when trying to construct the `Resource` object. It seems my only option is #3, to make a property that I can set - this just feels wrong. – skaz Nov 19 '11 at 20:13
1

Class should take whatever dependencies it needs, in order to perform its function. Both other services it delegates some tasks to, as well as primitive dependencies (which are usually some configuration values).

Any non-trivial container will cater for this scenario and allow you to do this. Here's for example how Castle Windsor does it.

Krzysztof Kozmic
  • 27,267
  • 12
  • 73
  • 115