2

I've been using AutoFac for some time now to take care of the dependency injection we're using in a web project. All is well, but I now want to demonstrate DI outside of an AutoFac context for reasons irrelevant to this question.

In doing so, I'm having to read up on 'manual' methods of achieving this pattern. All of the examples in tutorials work (obviously), but the issue of tightly coupled objects still exist.

Take this for example: http://www.devx.com/dotnet/Article/34066/0/page/2

The constructor of the dependent class takes an interface:

public class BusinessFacade {
    private IBusinessLogic businessLogic;
    public BusinessFacade(IBusinessLogic businessLogic) {
        this.businessLogic = businessLogic;
    }
}

But then the instantiation of BusinessFacade still requires a concrete implementation to be passed, which means an implementation needs to be instantiated:

IBusinessLogic productBL = new ProductBL();
BusinessFacade businessFacade = new BusinessFacade(productBL);

Question

Now I know, somewhere at some point, something (whether it is a container or manually written code) will have to decide on the implementation to choose, but how can I come to terms with the benefit of moving such decision outside of the dependent class? Of course the BusinessFacade class is no longer tightly coupled, but we're still very explicit about which implementation we choose - so what's been gained here? Is it purely for the fact we can mock out the dependencies?

  • 1
    You are aware that your IoC container is injecting (passing) concrete implementations too, right? I mean, just because you don't see it doesn't mean it isn't happening. You should still be composing all of your dependencies in the composition root, even if you do it by hand. It just sucks to do it by hand and looks awful, so people tend to either use an IoC or scatter their dependency creation around the code base. – RubberDuck Sep 5 '15 at 1:30
0

The fact that a BusinessFacade object can take any such implementation of IBusinessLogic is such that you are decoupled so long as you follow SOLID principles of design in your objects.

The typical idea that you brought up that ProductBL property can now be mocked in a unit test is one particular benefit that you mentioned. The other is that if you have requirements in the future for additional IBusinessLogic implementations then you can simply use the same BusinessFacade class and create many container managed objects of type BusinessFacade that could be wrapping many various implementations. You probably will organize them and name them properly in your DI configuration.

It may seem pointless, but probably only because of what it is I think you are doing.

All is well, but I now want to demonstrate DI outside of an AutoFac context for reasons irrelevant to this question.

If you are newing up objects outside of your container like in your code example then how is that Dependency Injection? If AutoFac doesn't monopolize DI in your project then how can any of your code have any reasonable assurance as to unstated and unconfigured dependencies that could exist in an object? This is really beyond the scope of your question but I thought it was worth mentioning that you might not be seeing the benefits of DI simply because it sounds to me from an outsiders perspective that you are purposely trying to circumvent it and work against it.

Now I know, somewhere at some point, something (whether it is a container or manually written code) will have to decide on the implementation to choose,

The container should always choose or what is the point of using DI at all.

  • Bit more context: I'll have an interview in the coming weeks, one part of which will be a technical test. I'd like to demonstrate awareness of patterns I've used, and although I've had a reliance upon AutoFac, I think I'd like to incorporate DI into what I produce without AutoFac. I also want to unit test 'properly'. I'm not sure I understand what you mean fighting against it - do you mean the examples I'm following are bad? Or are they just that way purely for demonstration sake? Is it the case that without a framework/container - DI is not as effective/wrong? Thanks very much for your reply. – JᴀʏMᴇᴇ Sep 3 '15 at 16:08
  • @JayMee I am not saying that DI could not or should not be done without a framework. What I am saying is that whether you use a framework or roll your own using Factory pattern, it should be an all or nothing. If you choose to Roll Your Own then you should do so exclusively and not having competing containers. It sounded as if you were trying to do your own DI when you are already using AutoFac for your project. – maple_shaft Sep 3 '15 at 16:58
2

The whole purpose of DI is to decouple concrete classes from each other. Your example is a good example of DI: BusinessFacade only knows about the IBusinessLogic interface and is passed an implementation of that interface. Other code then decides the instance to pass in. That "other code" might be a container if you are using IoC (such as with AutoFac), it might be hand-rolled code if you are using "poor man's DI" (as in your example), or it might be a mock when unit testing.

Declaring an instance of an interface and then passing it in to another class does not create tight coupling; it remains loosely coupled as the two are only bound together at runtime. For the live application, you want to perform all such instantiation and injection in one place (eg, the container). Unit tests will instantiate and inject in many places as they are deliberately only testing small parts of the code.

There are clear benefits to this approach. Your code is not only easier to test (as mocks can be injected in place of complex business logic) but it makes the code more maintainable too, for it's easier to understand the implications of a change when that change isn't tightly coupled to numerous disparate parts of a system.

2

Sometimes it helps to be really explicit:

  • BusinessFacade is tightly coupled to IBusinessLogic because it uses it in it's constructor signature
  • ProductBL is tightly coupled to IBusinessLogic because it implements the interface
  • The 2-line composer in your example is tightly coupled to IBusinessLogic, BusinessFacade and ProductBL because it creates objects of those types

So there still is a lot of tight coupling going on. That isn't surprising, DI does not intend to make everything loosely coupled. The remaining tight coupling makes sure that there are no runtime errors because of type mismatches.

Decoupling

The main goal of DI is to decouple components from the concrete dependencies that are used when the application is running.

Why would you want that? One possible reason is that you do not know the final applications in which it will run. Maybe because you want your components to support future applications that are not written yet, maybe applications are written by a third party.

Another aspect is that by having an interface as dependency it is much clearer what the component actually depends on: exactly the members of the interface. And you know that everything not explicitly specified in the interface can be changed without touching the code of your component, just by supplying another concrete dependency.

Compositon

I would argue that injecting dependencies even is worth it when you are injecting concrete dependencies - it allows the use of a single composition root for the whole application which documents the application structure.

But with concrete dependencies there isn't a lot you can change. If you are using components that depend on interfaces there is a lot you can easily tweak and adjust at the system composition layer. Even a simple facade with logging-functionality or a caching-component at the right spot can provide huge value with minimal to no changes to existing code.

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.