Search code examples
c#design-patternsdependency-injectionfactorycross-cutting-concerns

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();
}

Solution

  • 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).