Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Constructor injection (DI) vs. static factories for cross cutting concerns?

In most arbitrary applications, there are many cross cutting concerns that need to be addressed among all available layers, e.g. logging, message bus, configuration. What I noticed is that in some classes, they tend to completely blow up the constructor if the modules are being injected using an IoC.

public class MyService : IService 
{
    public MyService(ILogger logger, IAppSettings settings, IEventBus eventBus...)
    {

    }
}

For usual cases of constructor over-injection, I tend to refractor the concerns into building blocks that belong closely together so I get fewer dependencies in a class. However, this is not possible with cross cutting concepts.

Among logging frameworks, static factories / services seem to very popular, e.g.

// Application root
MyLoggerService.SetFactory(log4NetFactory);

// Somewhere
MyLoggerService.GetLogger("name") // returns Log4NetLogger created by Log4NetFactory.

My question is: Is this approach a good one, for all kinds of cross cutting stuff? What are the drawbacks if the code may end up looking like this:

public class MyService : IService
{

    private readonly IReallyNeedThat _dependency;

    public MyService(IReallyNeedThat dependency)
    {
        _dependency = dependency;
    }

    private readonly ILogger _logger = LoggerService.GetLogger("MyService");
    private readonly IEventBus _eventBus = EventBusService.GetEventBus();
    private readonly IConfiguration _configuration = ConfigurationService.GetConfiguration(Level.Roaming)
    private readonly IExceptionHandler _exceptionHandler = ExceptionPolicy.GetHandler();
    private readonly ITracer _tracer = TraceManager.GetDebugTracer();
}
like image 279
xvdiff Avatar asked Aug 11 '14 11:08

xvdiff


People also ask

What is the limitation of constructor injection?

The main disadvantage to Constructor Injection is that if the class you're building is called by your current application framework, you might need to customize that framework to support it. Some frameworks assume that your classes will have a parameterless constructor.

Which dependency injection method is better?

If a dependency is used in only one spot, method injection (covered below) might be a better choice. Constructor injection should be the main way that you do dependency injection. It's simple: A class needs something and thus asks for it before it can even be constructed.

Which are considered to be typical common crosscutting concerns that would be a good fit for a AOP?

For example, logging, security and data transfer are the concerns needed in almost every module of an application, thus they are the cross-cutting concerns.

What is the main reason for using the dependency injection design pattern?

A form of inversion of control, dependency injection aims to separate the concerns of constructing objects and using them, leading to loosely coupled programs. The pattern ensures that an object or function which wants to use a given service should not have to know how to construct those services.


2 Answers

Moving the dependencies out of the constructor doesn't solve the problem, because you don't lower the amount of dependencies a class has and chances are big that you are still violating Single Responsibility principle and the Open/Close principle, causing your code to be hard to test, hard to change and hard to maintain.

Instead often a good solution is to pull those cross-cutting concerns out of your components and place them into components that are specially tailored for that cross-cutting concern and that component wrap the original component. In other words: create decorators.

This does probably force you to change the design of your classes, because when you don't have generic abstractions to define sets of related services, you will have to define a decorator per abstraction and that would cause a lot of code duplication, which is bad in almost all cases.

So instead, model your system around command/handlers and query/handlers and you'll be in a much better place. You can decorate each piece of business logic with a generic decorator that you define once and reuse all over the place. This keeps your system clean but still very flexible.

like image 183
Steven Avatar answered Sep 20 '22 00:09

Steven


If you are more onto TDD, you can guess easily which approach is better.

With dependency injection, your code becomes more (unit)testable. You can inject dependencies via some mocking framework and create your unit tests without much headache.

But in case of static factories, since your factory classes are (hard)wired into your class, while unit testing there is no way out how you can inject them from outside your class.

Benefits of DI over static factories -

  1. Concurrent Development - Think of a logging service that you are consuming, which is being built by somebody else and you are going to unit test your code (and you don't care unit testing of the logging service since you assume, it should be unit tested when you use it) . You batter use DI, inject the dependency using a mock object and done.

  2. Speed - While unit testing your classes, definitely you wouldn't want them to take long time (so that it gives you a coffee break with every single change to your main class ;) ). You would definitely want you unit test to run in a blink of eye and report any error. Static factory that depends on external resources (e.g. network/DB, FileSystem) is going to take time. You better use DI, use a mock object and done.

  3. Testability - DI helps isolating the client from their dependencies (promotes use of Interfaces), hence improves Testability (via use of mocks).

like image 27
Rabi Avatar answered Sep 18 '22 00:09

Rabi