views:

484

answers:

3

I'm trying to come to terms with using IoC/Dependency Injection while at the same time programming to contracts rather than specific classes. The dilemma I'm having is the tension between:

  1. Do program to interfaces for IoC: I started out with IoC relying heavily on interfaces. Judging by Spring's sample projects, interfaces are the way to go when programing to a contract with IoC.

  2. ( ... although abstract classes generally preferred: the main drawback of interfaces is that they are much less flexible than classes when it comes to allowing for evolution of APIs )

  3. Do make class dependencies explicit via constructor My gut feeling is that it's good programming practice to pass dependencies in to a class's constructor. Indeed, this is dependency injection.

  4. ... except you can't enforce constructor signature in interfaces/abstract clases: Neither interfaces or nor abstract classes allow for defining a constructor signature ( easily / elegantly ). See also Framework Design Guidelines section 4.4: DO NOT define public or protected internal constructors in abstract types. ... Constructors should be public only if users will need to create instances of the type.

This question is related to a previous stackoverflow question: Interface defining a constructor signature?

But my question is:

Since you can't define a constructor in a C# interface/abstract class, as the question above asks, on a practical level:

How do you reconcile this with the sensible practice of passing dependencies in via a constructor?

Edit: Thank you for the answers. I'm hoping for some insight on what I should do in this case. Just not use contructor args? Use some sort of Init() method that does take the dependencies? Edit2: Thanks for the great answers, very helpful.

+1  A: 

Your IoC container must construct an object from a concrete type, even though what you're passing around is an interface. Your constructor is not a behavior or state contract, so it does not belong in an interface or as a public member of your abstract class.

A constructor is an implementation detail, so you do not need to separate its definition from the concrete class.

Michael Meadows
A: 

You cannot define constructor signatures in interfaces. That wouldn't make sense anyway since the interface shouldn't enforce how the implementations are constructed.

Abstract classes though can indeed have constructors. They must be protected since public constructors does not make sense either. They should only be called by concrete subclasses.

The IoC principle dictates that instead of having class A know about and instantiate class B, you should instead pass in a reference to IB to the constructor of A. Then A will not need to know about class B and thus you can easily substitute class B with some other implementation of IB.

Since you're passing in an already instantiated object of class B, the IB interface doesn't need to have a constructor signature.

Peter Lillevold
+5  A: 

I always think this is easier to explain with a (made up) example...

Imagine you have an ICustomerRepository interface, an IShoppingCartRepository interface and an ICheckout interface. You have concrete implementations of those interfaces - CustomerRepository, ShoppingCartRepository, and CheckoutService.

Your CheckoutService concrete class has a constructor that takes an ICustomerRepository and an IShoppingCartRepository - e.g.

public CheckoutService(ICustomerRepository customerRepository, IShoppingCartRepository shoppingCartRepository)
{
  // Set fields for use in some methods later...
  _customerRepository = customerRepository;
  _shoppingCartRepository = shoppingCartRepository;
}

Then, when you want an ICheckoutService implementation to do some work with, you tell your IoC container which concrete class it should use for each interface type and ask it to build you an ICheckoutService. Your IoC container will go and build your classes for you, injecting the correct concrete classes into the constructor of your CheckoutService. It will also build dependencies all the way down the class heirarchy here, so if, for example your ShoppingCartRepository takes an IDatabaseSession interface in the constructor, your IoC container will inject that dependency too, as long as you have told it which concrete class to use for your IDatabaseService.

Here's some code you might use when configuring (for example) StructureMap as your IoC container (this code would typically be called during app startup):

public class AppRegistry : Registry
{
  public AppRegistry()
  {
    ForRequestedType<ICheckoutService>().TheDefaultIsConcreteType<CheckoutService>();
    ForRequestedType<ICustomerRepository>().TheDefaultIsConcreteType<CustomerRepository>();
    // etc...
  }
}

Then to get an instance of ICheckoutService built up and ready to go, with all the dependencies passed into the constructor for you, you would use something like:

var checkoutService = ObjectFactory.GetInstance<ICheckoutService>();

I hope that makes sense!

Steve Willcock
Ah hah !So I *can* continue to use constructor arguments to be explicit about dependencies, while at the same time programming to a contract. But let the IoC container worry about injecting those dependencies correctly. Thank you, this clarifies it completely.
Jeffrey Knight