Question

The fifth concept in the SOLID principle is the dependency inversion principle. It is heavily related to dependency injection, and Inversion of control, and when any of these concepts are mentioned, they are often used in a way that makes them synonymous with each other. Example:

Autofac is an addictive Inversion of Control container for .NET Core, ASP.NET Core, .NET 4.5.1+, Universal Windows apps, and more.

and

the Spring Framework implementation of the Inversion of Control (IoC) principle. IoC is also known as dependency injection (DI).

I am defining automatic factories here as factories that construct objects based on configuration. Autofac and Spring are two examples. Technically the are designed as IoC Containers, but broadly speaking they are used as automatic factories.

I often hear people calling Autofac, or Spring IoC "Dependency Injection" frameworks. Example:

We can call this as our IoC (Inversion of Control) container or a DI (Dependency Injection) framework.

So much of the online documentation seems to bring along with it the baggage of automatic factories. On the face of it, the SOLID principle does not seem to formally require automatic factories for constructing objects. But, is it a consequence of dependency inversion that automatic factories are required to correctly implement the SOLID principle? If the highest level of the app constructs the dependencies and then passes them in to the constructor of the highest level class, is this following the SOLID principle? Or, are IoC Containers required for this?

Take this C# Example

    public interface IMessageSender
    {
        void SendMessage(string message);
    }

    public class ConsoleMessageSender : IMessageSender
    {
        public void SendMessage(string message)
        {
            Console.WriteLine(message);
        }
    }

    public interface IApp
    {
        void SendHelloMessage();
    }

    public class App : IApp
    {
        private IMessageSender _messageSender;

        public App(IMessageSender messageSender)
        {
            _messageSender = messageSender;
        }

        public void SendHelloMessage()
        {
            _messageSender.SendMessage("Hello World!");
        }
    }

Here is Version A) without IoC / Automatic Factories:

    class Program
    {
        static void Main(string[] args)
        {
            var app = new App(new ConsoleMessageSender());
            app.SendHelloMessage();
        }
    }

Here is Version B) with Autofac for the IoC container

    class Program
    {
        static void Main(string[] args)
        {
            var builder = new ContainerBuilder();
            builder.RegisterType<ConsoleMessageSender>().As<IMessageSender>();
            builder.RegisterType<App>().As<IApp>();
            var container = builder.Build(ContainerBuildOptions.None);
            var app = container.Resolve<IApp>();
            app.SendHelloMessage();
        }
    }

Is Version B) more correct from a SOLID point of view? Would Version A) fail to conform to the SOLID principle because of the lack of an IoC container?

Note: I'm looking for a clear definition here. IoC containers are often bundled up with the concept of DI and SOLID, but the question is about whether or not they are strictly required. There is a question of whether or not they are accoutrement that have been added to SOLID over time

Was it helpful?

Solution

Is it a consequence of dependency inversion that automatic factories are required to correctly implement the SOLID principle?

No.

IoC Containers are merely a convenient way to instantiate objects. They're not a mandate for SOLID. You can instantiate the same objects without a container and still be SOLID.

If the highest level of the app constructs the dependencies and then passes them in to the constructor of the highest level class, is this following the SOLID principle?

Essentially, yes.

Your aggregate root (which could simply be your main method, if it's a console application) is responsible for standing up the object graph that makes your program (or aggregate) work.

Is Version B) more correct from a SOLID point of view?

No.

SOLID principles are based on classes and class hierarchies, not containers. Containers are one way to stand up an object graph, but they're not the only way. SOLID doesn't depend on containers.

Would Version A) fail to conform to the SOLID principle because of the lack of an IoC container?

No.

OTHER TIPS

I feel your pain on the confusion of Dependency Injection and Dependency Inversion. I've been on many job interviews and having to explain the difference.

I wouldn't say IoC containers are required, but they do make the instantiation of big dependency trees much easier. But using or not using IoC container has no bearing on if the code follows SOLID. In ideal codebase, code should have no knowledge about IoC container it resides in, if any.

Dependency Inversion often leads to many classes that need other classes that need other classes, with some classes being used by many other classes and often with different lifetimes. Your example doesn't do this problem justice, as you have only two classes. Instead, imagine an example with hundred of classes, even more interfaces (as class can expose multiple interfaces) and complex non-cyclical graph of dependencies between them. In this kind of example, the manual instantiation code becomes much more complicated and confusing than just IoC's combination of registration and resolution.

Licensed under: CC-BY-SA with attribution
scroll top