I am currently attempting to learn the benefits of using an IoC container and familiarize myself with DI. I've started to use StructureMap since it seems rather simplistic and yet powerful.
I want to verify that my understanding of these concepts are correct. Let's assume the following rudimentary classes in an application (details ommited for brevity):
public class OrderService : IOrderService
{
private IOrderRepository _repository;
private ITaxCalculator _taxCalculator;
private IShippingCalculator _shippingCalculator;
public OrderService(IOrderRepository repository,
ITaxCalculator taxCalculator,
IShippingCalculator shippingCalculator)
{
this._repository = repository;
this._shippingCalculator = shippingCalculator;
this._taxCalculator = taxCalculator;
}
public IOrder Find(int id) { return this._repository.Find(id); }
}
public class OrderRepository : IOrderRepository
{
public IOrder Find(int id) { // ... }
}
public class StandardShippingCalculator : IShippingCalculator
{
// ...
}
public class StandardTaxCalculator : ITaxCalculator
{
private ITaxSpecification _specification;
public StandardTaxCalculator(ITaxSpecification specification)
{
this._specification = specification;
}
}
First and foremost, the Dependency Inversion Principle states that since the OrderService is a "high-level" module it houldn't depend on the implementation details of anything lower level, it should just have references to those classes and be able to ask them to do their thing without having to know what it's doing, and the consuming code should be responsible for creating and handing these preconfigured modules to it. Is that right? Therefore, DI keeps these classes loosely coupled so that they don't have to know the exact way a method on that dependency is being called, simply that it will be called and do whatever it needs to do - the OrderService doesn't care if the Repository is querying XML, or using NHibernate or EF or even raw DataSets; it just knows that it can call into the Repository, tell it to find a Order with an ID of 42, and the repository will know what to do.
It's also my understanding that an IoC container, StructureMap in this case, provides a benefit by not forcing us to make sure we're creating all these dependencies by hand and passing them in. For example, the Main method of a trivial app using the above code might have:
static void Main(string[] args)
{
IOrderService service = new OrderService(
new OrderRepository(), new StandardShippingService(),
new StandardTaxService(new StandardTaxSpecification()));
IOrder order = service.Find(42);
// Do something with order...
}
which is revoltingly ugly with all the news to set it up; even if I created variables it's still ugly. The use of the IoC container lets me avoid all of this, and in the case of StructureMap it would become:
static void Main(string[] args)
{
ObjectFactory.Initialize(x =>
{
x.For<IOrderRepository>().Use<OrderRepository>();
x.For<IOrderService>().Use<OrderService>();
x.For<IOrder>().Use<Order>();
x.For<IShippingCalculator>()
.Use<StandardShippingCalculator>();
x.For<ITaxCalculator>().Use<StandardTaxCalculator>();
x.For<ITaxSpecification>()
.Use<StandardTaxSpecification>();
});
IOrderService service =
ObjectFactory.GetInstance<IOrderService>();
IOrder order = service.Find(42);
// do stuff with order...
}
Which is much cleaner, easier to maintain, and lets me just sub out the concrete class for, say, a Mock if I was writing a unit test. In short, the benefit is that it decouples everything even more to where I don't even have to care (in the calling code, that is) what a particular class depends on, I can just create one using the container and let it do it's thing and ensure the consuming code only knows what it needs to - for instance in a real app if the Controller is calling the service, it doesn't need to know about Repositories or Calculators or Specifications, all it needs to know is to use the OrderService to do something with an Order.
Is this understand correct? On that note, there is a few things I'm not sure of yet:
If you decide to use an IoC container, is it meant to be used everywhere in the application, only where you have many inverted dependencies to resolve, or only in the consumer? For example, in the OrderRepository if I'm using a concrete implementation and newing up an Order; would this class be using StructureMap as well to get the Order? This might be a somewhat silly question but all of the DI/IoC examples I've seen only focus on using it in the consuming client (e.g. a webpage), and never touch on using it elsewhere. It seems like it's an all-or-nothing approach: If you're going to use an IoC container then it gets used everywhere; you are essentially replacing any call to new SomeObject();
with, in this case, ObjectFactory.GetInstance<ISomeObject>();
Is it considered good or bad to have every class (where possible, of course) derive from an interface whether or not there's a need to use DI/IoC or something like mocking it? I've seen many code examples where every single class that's not a built-in one has an interface behind it, and while I can see the benefits and possible future-proofing of doing this and I suppose that following TDD or BDD might be a factor here as using those methodologies will usually tell you if you need an interface for a class, but I've seen and spoken to many people who, TDD or not, feel that you should never define an object's type as a concrete class; it should always be an interface or abstract class as the underlying type. That seems like it's a case of the "Needless Complexity" code smell, not to mention a violation of YAGNI.
Both your questions concern controversial topics, but I'll weigh in on my side of the debates.
If you decide to use an IoC container, is it meant to be used everywhere in the application, only where you have many inverted dependencies to resolve, or only in the consumer?
Your top-level application (the consumer) is the only component that should know about your dependency injection framework. You don't need to replace new
throughout your codebase because each object should have all the dependency instances it needs to do its job (Miško Hevery's "Dependency Injection Myth: Reference Passing" was what finally drove this home for me).
Is it considered good or bad to have every class (where possible, of course) derive from an interface whether or not there's a need to use DI/IoC or something like mocking it?
The rest of this question shows that you already know the answer to this: only build interfaces to create more suitable abstractions (than the concrete class in question) or to provide some other value.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With