Dot Net For All

Dependency Inversion : SOLID principle

Dependency inversion can be difficult to understand, if you are not aware what problem it is solving. This is the fifth and last SOLID principle.

In this article I will help you to understand this SOLID and object oriented principle with very easy and practical example with code examples.

What is dependency inversion or inversion of Dependency?

As per Robert C Martin’s book the definition of dependency inversion principle is:

Big benefit of Object oriented programming is to manage dependency.

Let’s suppose we are working on the two separate projects in our source control. Let’s call them module A and B. You can call them project or assemblies whatever you like.

Now module A depends on module B and we included a reference to B’s dll in module A. Further we have a method in module A which uses the reference to module B and creates and instance of the class of B. Basically module A holds the reference to function in module B.

It means there is a dependency from module A to module B as shown in the figure below.

Now the above dependency has two components, clearly at run time there is a flow of control from module A to module B. In programming languages like C# or Java, there is a statement like using to declare respectively which can help us to include reference to project B, it is this source code dependency that we are interested in.

What if we want to deploy module A and module B separately. In the above scenario where they are dependent on each other and tightly coupled they can’t be deployed independently. They can’t even be compiled independently, any source code change to module B will force recompile and redeploy module A.

Object oriented allows us to handle this source code dependency in a better way. It allows us to remove source code dependency and leaves us with run time dependency.

As you can see in the figure above, the module A uses the interface in place of the concrete class as shown in the previous figure and module B implements the interface.

This makes module A independent of module B and removes the dependency

Dependency Inversion : Code Example

Lets try to understand the dependency inversion principle with code example. Below is an example of the Translator class example. This is our main worker class which will be called by clients to translate the meaning of word. This class we can treat as high level module.

Initially we had a scope to translate the word to only English language. That is why we added EnlishTranslator class. This is our low level module.

public class Translator{
        private string word;
        public Translator(string word){
            this.word = word;
        }

        public string TranslateToEnglish(EnglishTranslator p_englishTranslator){
            return p_englishTranslator.Translate(word)
        }
    }
    
    public class EnglishTranslator{
        IDictionary<string, string> translations = new Dictionary<string, string>();
        public string Translate(string input){
            string translation;
            translations.TryGetValue(input, out translation);
            return translation;
        }
    }

After this implementation your management was very happy and you were a star as you completed the project in a very small time and it is quite efficient.

But after some days management thought, something is missing and they want to grow the revenue by introducing more more translation. They want to translate to French. You thought it should be OK as you have to add one new class and a new method to Translator class. And you come up with below class.

public class Translator{
        private string word;
        public Translator(string word){
            this.word = word;
        }

        public string TranslateToEnglish(EnglishTranslator p_englishTranslator){
            return p_englishTranslator.Translate(word);
        }

        public string TranslateToFrench(FrenchTranslator p_frenchTranslator){
            return p_frenchTranslator.Translate(word);
        }
    }

public class FrenchTranslator{
        IDictionary<string, string> translations = new Dictionary<string, string>();
        public string Translate(string input){
            string translation;
            translations.TryGetValue(input, out translation);
            return translation;
        }
    }

Now comes the real challenge, after you have created new FrenchTranslator you have to compile and deploy both the high level and low level module i.e Translator and FrenchTranslator containers. And other draw back is you have to change the Translator class every time you are adding a new translation feature to your project.

And below is the much cleaner, easier to maintain and highly independent code. In the below code out high level module i.e translator does not depend on low level module i.e. EnglishTranslator or FrenchTranslator.

Instead both depends on abstraction i.e. ITranslator.

And client can call the translator method by creating and instance of type ITranslator at run time.

public class Translator{
        private string word;
        public Translator(string word){
            this.word = word;
        }

        public string Translate(ITranslator p_Translator){
            return p_Translator.Translate(word);
        }

    }

    public interface ITranslator(){
        public string Translate(string word);
    }
    
    public class EnglishTranslator: ITranslator{
        IDictionary<string, string> translations = new Dictionary<string, string>();
        public string Translate(string input){
            string translation;
            translations.TryGetValue(input, out translation);
            return translation;
        }
    }

    public class FrenchTranslator: ITranslator{
        IDictionary<string, string> translations = new Dictionary<string, string>();
        public string Translate(string input){
            string translation;
            translations.TryGetValue(input, out translation);
            return translation;
        }
    }

Conclusion:

Module dependencies are tricky to handle if they are not handled properly in the projects and they can create a mess out of your project. I personally have worked on projects where they are not handled properly and its really a pain to compile lots of projects at same time. Dependency inversion is a very nice solution to get out of this pain.

Top career enhancing courses you can't miss

My Learning Resource

Excel your system design interview