4

Suppose I have MyClass with a very simple dependency. It uses constructor injection.

public class MyClass : IMyClass
{
    private IA A;

    public MyClass(IA a)
    {
        A = a;
    }
}

This code get shipped and some other developers are using it.
At some point in the future I need to add in a second dependency, on IB.

How should I add this dependency on IB?

Some options, and why I disapprove:

  • Just add it to the constructor
    • Braking change.
  • Inheritance or the decorator pattern.
    • Extra classes and code bloat.
    • New class will have boilerplate code passing around the IA.
    • I have no guarantee that other developers will switch to using the new class.
  • Use a service locator to populate the new IB field.
    • I'm now using two different types of injection for extra confusion.

It seems to me that constructor injection is just not easily extensible.

  • 1
    If you just add a new field via the constructor, then that doesn't seem to add any value. You will only add a new field or dependency if it is being used. Which means you'd also have to change the code itself to use the new dependency. – jordan May 8 '14 at 12:18
  • 7
    Adding a required dependency is a breaking change, no matter how you inject that dependency. – CodesInChaos May 8 '14 at 12:57
  • @CodesInChaos, wouldn't say it needs to be a breaking change. For example, if I write private IB B = new B();, doesn't break anything. Only when we try to use constructor injection do we see a breaking change. Do you agree? – Swesus May 8 '14 at 13:52
3
  1. Create an implementation of IB that contains whatever behavior MyClass currently possesses that is being extracted, or if IB provides new functionality, then a sensible default implementation that preserves MyClass's current semantics.
  2. Add IB dependency to MyClass via a new constructor.
  3. Have the old constructor create an instance of the implementation of IB you made in step 1.

Old code still works, new code can provide alternate behavior as desired.

  • So you are saying, create an "empty" implementation of IB, which the old contructor can use? – Swesus May 8 '14 at 12:37
  • A couple of reasons why I'm not 100% happy with this solution. 1) Code bloat of this empty class. 2) I have no guarantee that other developers will switch to using the new non-empty class. – Swesus May 8 '14 at 12:52
  • 1
    Isn't a “guarantee developers will switch” the definition of breaking change? – Dan May 8 '14 at 13:01
  • The implementation doesn't have to be empty. I don't know what you're trying to do so I don't know what constitutes a sensible default implementation. – Doval May 8 '14 at 14:10
1

If MyClass needs to have an IB to function, then there is not really a choice. Any non-breaking change would just results in bugs because the others will keep using MyClass without providing the required IB object, so you can just as well prevent that and make the new dependency a required parameter of your constructor.

If the dependency on IB is optional, then you have a few options:

  • Derive a new MyClass_version2 from MyClass and provide all the new IB-related behavior from there. This will likely work best if there is little overlap between the existing behavior and the extensions.
  • Add the new IB dependency to MyClass, but ensure to set it to null in the existing constructor and ensure that all methods can handle a null IB. Then add an overload of the constructor MyClass(IA a, IB b).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.