Movatterモバイル変換


[0]ホーム

URL:


Skip to content
DEV Community
Log in Create account

DEV Community

Cover image for Dependency Inversion Principle | SOLID as a Rock
Vishal Chovatiya
Vishal Chovatiya

Posted on • Edited on • Originally published atvishalchovatiya.com

     

Dependency Inversion Principle | SOLID as a Rock

DependencyInversionPrinciple(in C++) is the fifth & last design principle of a series SOLID as a Rock design principles. The SOLID design principles focus on developing software that is easy to maintainable, reusable & extendable. In this article, we will see an example code with the flaw & correct it with help of DIP. We will also see guideline & benefits of DIP in closure of the article.

/!\: This article has been originally published on myblog. If you are interested in receiving my latest articles,please sign up to my newsletter.

By the way, If you haven't gone through my previous articles on design principles, then below is the quick links:

  1. SRP -- Single Responsibility Principle
  2. OCP -- Open/Closed Principle
  3. LSP -- Liskov Substitution Principle
  4. ISP -- Interface Segregation Principle
  5. DIP -- Dependency Inversion Principle

The code snippets you see throughout this series of articles are simplified not sophisticated. So you often see me not using keywords likeoverride,final,public(while inheritance) just to make code compact & consumable(most of the time) in single standard screen size. I also preferstruct instead ofclass just to save line by not writing "public:" sometimes and also missvirtual destructor, constructor,copy constructor, prefixstd::, deleting dynamic memory, intentionally. I also consider myself a pragmatic person who wants to convey an idea in the simplest way possible rather than the standard way or using Jargons.

Note:

  • If you stumbled here directly, then I would suggest you go throughWhat is design pattern? first, even if it is trivial. I believe it will encourage you to explore more on this topic.
  • All of this code you encounter in this series of articles are compiled using C++20(though I have usedModern C++ features up to C++17 in most cases). So if you don't have access to the latest compiler you can usehttps://wandbox.org/ which has preinstalled boost library as well.

Intent

=> High-level modules should not depend on low-level modules. Both should depend on abstractions.
=> Abstractions should not depend on details. Details should depend on abstractions.

  • Above lines might seem cryptic at first but don't stick here keep going. You will get it by example.

What are the High-level & Low-level modules?

=>High-level modules:describes operations which is more abstract in nature & contain more complex logic. These modules orchestrate low-level modules in our application.
=>Low-level modules:describes implementations more specific & individual to components focusing on details & smaller parts of the application. These modules are used inside the high-level modules.

Violating Dependency Inversion Principle

enumclassRelationship{parent,child,sibling};structPerson{stringm_name;};structRelationships{// Low-level <<<<<<<<<<<<-------------------------vector<tuple<Person,Relationship,Person>>m_relations;voidadd_parent_and_child(constPerson&parent,constPerson&child){m_relations.push_back({parent,Relationship::parent,child});m_relations.push_back({child,Relationship::child,parent});}};structResearch{// High-level  <<<<<<<<<<<<------------------------Research(constRelationships&relationships){for(auto&&[first,rel,second]:relationships.m_relations){// Need C++17 hereif(first.m_name=="John"&&rel==Relationship::parent)cout<<"John has a child called "<<second.m_name<<endl;}}};intmain(){Personparent{"John"};Personchild1{"Chris"};Personchild2{"Matt"};Relationshipsrelationships;relationships.add_parent_and_child(parent,child1);relationships.add_parent_and_child(parent,child2);Research_(relationships);returnEXIT_SUCCESS;}
Enter fullscreen modeExit fullscreen mode
  • When later on the container ofRelationships changes fromvector toset or any other container, you need to change in many places which isn't a very good design. Even if just the name of data member i.e.Relationships::m_relations changes, you will find yourself breaking other parts of code.
  • As you can see Low-level module i.e.Relationships directly depend on High-level module i.e.Research which is essentially a violation of DIP.

Dependency Inversion Principle Example

  • Rather we should create an abstraction and bind Low-level & High-level module to that abstraction. Consider the following fix:
structRelationshipBrowser{virtualvector<Person>find_all_children_of(conststring&name)=0;};structRelationships:RelationshipBrowser{// Low-level <<<<<<<<<<<<<<<------------------------vector<tuple<Person,Relationship,Person>>m_relations;voidadd_parent_and_child(constPerson&parent,constPerson&child){m_relations.push_back({parent,Relationship::parent,child});m_relations.push_back({child,Relationship::child,parent});}vector<Person>find_all_children_of(conststring&name){vector<Person>result;for(auto&&[first,rel,second]:m_relations){if(first.name==name&&rel==Relationship::parent){result.push_back(second);}}returnresult;}};structResearch{// High-level <<<<<<<<<<<<<<<----------------------Research(RelationshipBrowser&browser){for(auto&child:browser.find_all_children_of("John")){cout<<"John has a child called "<<child.name<<endl;}}//  Research(const Relationships& relationships)//  {//    auto& relations = relationships.relations;//    for (auto&& [first, rel, second] : relations)//    {//      if (first.name == "John" && rel == Relationship::parent)//      {//        cout << "John has a child called " << second.name << endl;//      }//    }//  }};
Enter fullscreen modeExit fullscreen mode
  • Now no matter, the name of container or container itself changes in Low-level module, High-level module or other parts of code which followed DIP will be in-tact.
  • The Dependency Inversion Principle (DIP) suggest that the most flexible systems are those in which source code dependencies refer only to abstractions, not to concretions.
  • This is the reason why most experienced dev uses STL or library functions along with generic containers. Even using anauto keyword at appropriate places may help in creating generic behaviour with less fragile code.
  • There are many ways you can implement DIP, as long as C++ concerns most people use static polymorphism(i.e.CRTP unless they need dynamic one),template specialization,Adapter Design Pattern,type-erasure, etc.

Yardstick to Craft Dependency Inversion Principle(DIP) Friendly Software

  • If you find enforcing DIP difficult then just design abstraction first & implement your high-level module on the bases of abstraction. Without having any knowledge of the low-level module or its implementation. Because of this process DIP is also known asCoding To Interface.
  • Keep in mind that all Low-level-modules/subclasses adhere to theLiskov Substitution Principle. This is because the Low-level-modules/subclasses will be used via the abstract interface, not the concrete classes interface.

Benefits

=> Reusability

  • Effectively, the DIP reduces coupling between different pieces of code. Thus we get reusable code.

=> Maintainability

  • It is also important to mention that changing already implemented modules is risky. By depending on abstraction & not on concrete implementation, we can reduce that risk by not having to change high-level modules in our project.
  • Finally, DIP when applied correctly gives us flexibility and stability at the level of the entire architecture of our application. Our application will be able to evolve more securely and become stable & robust.

Conclusion

As you can see we took a basic example of code & converted it into a reusable, flexible & modular piece of code. If I would have to summarize DIP in simple & short sentence then it would be like:

Do not use the concrete object directly unless you have a strong reason to do so. Use abstraction instead.

DIP trains us to think about classes in terms of behaviour, rather than construction or implementation.

Have Any Suggestions, Query or Wants to SayHi? Take the Pressure Off, You Are Just a Click Away.🖱️

Top comments(0)

Subscribe
pic
Create template

Templates let you quickly answer FAQs or store snippets for re-use.

Dismiss

Are you sure you want to hide this comment? It will become hidden in your post, but will still be visible via the comment'spermalink.

For further actions, you may consider blocking this person and/orreporting abuse

Software Developer⌨, Fitness Freak🏋, Hipster🕴, Blogger👨‍💻, Productivity Hacker⌚, Technical Writer✍️, Tech talker👨‍🎤, Leader👨‍🔬, Always a Student👨‍🎓, Incomplete🔍 & Learning Junkie📚.
  • Location
    Bengaluru
  • Education
    B.Tech in Electronics & Telecommunication
  • Work
    Senior Staff @ Infineon Technologies
  • Joined

More fromVishal Chovatiya

DEV Community

We're a place where coders share, stay up-to-date and grow their careers.

Log in Create account

[8]ページ先頭

©2009-2025 Movatter.jp