ArticleAugust 21, 2026

S.O.L.I.D Principles ( System Design)

S.O.L.I.D Principles ( System Design)

SOLID is an acronym for five design principles that make software designs more understandable, flexible, and maintainable.

Single Responsibility Principle (SRP)

 A class should have only one reason to change, meaning it should have only one job or responsibility.

Bad Example (C++ Code) :

class User { private:   string name;   string email; public:   void saveToDatabase() {     // Database logic here   }       void sendEmail() {     // Email sending logic here   }       void generateReport() {     // Report generation logic here   } };

Good Example:

#include<bits/stdc++.h> using namespace std; class User{   private:    int id;    string name;    string emailAddress;       public:        User(int id, string name, string emailAddress){      this\->id = id;      this\->name = name;      this\->emailAddress = emailAddress;    }        int getId() const {      return id;    }        string getName() const {      return name;    }        string getEmailId() const {      return emailAddress;    }         }; class UserRepository{       public:    void saveToDB( User & u1){     int userId= u1.getId();     string userName = u1.getName();     string userEmail = u1.getEmailId();     cout<<"User Data "<< userId <<" , "<< userName<<", "<< userEmail <<"Saved In Db "<<endl;    } }; class EmailService{   public:            void emailSend( const User & u1){     int userId= u1.getId();     string userName = u1.getName();     string userEmail = u1.getEmailId();      cout<<"Email send to " << userName << "at his Email Address"<< userEmail<<endl;    } }; class UserStrategy{   private:        UserRepository ur;    EmailService um;        public:       //  User u1 (123, "alpha", "alpha@gmail.com");         void userAllServices( User &u1){     ur.saveToDB(u1);     um.emailSend(u1);           }         void userDataSaveService( User &u1){      ur.saveToDB(u1);    }         void userEmailSendService( User & u1){      um.emailSend(u1);    }                    }; int main(){       User u (1, "alpha", "alpha@gmail.com");       UserStrategy us;       us.userAllServices(u);       us.userEmailSendService(u);       us.userDataSaveService(u);         };

Key Benefit: Each class has a single, well-defined responsibility, making the code easier to maintain and test.

Open/Closed Principle (OCP)

Definition: Software entities should be open for extension but closed for modification.

Bad Example:

class
public:   double width, height; }; class Circle { public:   double radius; }; class AreaCalculator { public:   double calculateArea(void\* shape, string type) {     if (type == "rectangle") {       Rectangle\* rect = static\_cast<Rectangle\*>(shape);       return rect->width \* rect->height;     } else if (type == "circle") {       Circle\* circle = static\_cast<Circle\*>(shape);       return 3.14 \* circle->radius \* circle->radius;     }      return 0;   } };

Good Example:

// OCP -> class must be extensible not modified

using namespace std; class paymentMethod{       public:    virtual void pay() = 0;     }; class CardPayment : public paymentMethod{   private:    int cardNumber;        public:        CardPayment(int cardNumber){      this\->cardNumber = cardNumber;    }            void pay() override {      cout<<"Payment Done using card Number "<< cardNumber<<endl;    }              }; class UpiPayment : public paymentMethod{        private:    string upiId;        public:        UpiPayment(string upiId){      this\->upiId = upiId;    }            void pay() override {      cout<<"Payment Done using UPI ID "<< upiId<<endl;    }     }; class paymentProcessor{ // this is an orechestration layer/ Business we can add validation, retries, logging.       public:         void userPayment( paymentMethod \* m ){             // we can add validation       m->pay();             // loggings      // retries    }     }; int main(){   paymentMethod \*p1 = new CardPayment(123456);       paymentMethod \*p2 = new UpiPayment("abhi@334sbi");       paymentProcessor p;       p.userPayment(p1);       p.userPayment(p2);       p1->pay(); }

Key Benefit: New shapes can be added without modifying existing code, reducing the risk of breaking existing functionality.

Liskov Substitution Principle (LSP)

Definition: Objects of a superclass should be replaceable with objects of its subclasses without breaking the application.

Bad Example:

class Bird { public:   virtual void fly() {     cout << "Flying..." << endl;   } }; class Penguin : public Bird { public:   void fly() override {     throw runtime\_error("Penguins can't fly!");   } };

Good Example:

class Bird { public:   virtual void move() = 0;   virtual ~Bird() = default; }; class FlyingBird : public Bird { public:   void move() override {     fly();   }   virtual void fly() {     cout << "Flying..." << endl;   } }; class Penguin : public Bird { public:   void move() override {     swim();   }   void swim() {     cout << "Swimming..." << endl;   } }; class Sparrow : public FlyingBird { public:   void fly() override {     cout << "Sparrow flying..." << endl;   } };

Key Benefit: Substituting a derived class for a base class doesn't cause unexpected behavior.

Interface Segregation Principle (ISP)

Definition: No client should be forced to depend on methods it does not use. Split large interfaces into smaller, more specific ones.

Bad Example:

class Worker { public:   virtual void work() = 0;   virtual void eat() = 0;   virtual void sleep() = 0;   virtual ~Worker() = default; }; class Robot : public Worker { public:   void work() override {     cout << "Robot working..." << endl;   }   void eat() override {     // Robots don't eat - forced to implement   }   void sleep() override {     // Robots don't sleep - forced to implement   } };

Good Example:

class Workable { public:   virtual void work() = 0;   virtual ~Workable() = default; }; class Eatable { public:   virtual void eat() = 0;   virtual ~Eatable() = default; }; class Sleepable { public:   virtual void sleep() = 0;   virtual ~Sleepable() = default; }; class Human : public Workable, public Eatable, public Sleepable { public:   void work() override {     cout << "Human working..." << endl;   }   void eat() override {     cout << "Human eating..." << endl;   }   void sleep() override {     cout << "Human sleeping..." << endl;   } }; class Robot : public Workable { public:   void work() override {     cout << "Robot working..." << endl;   } };

Key Benefit: Classes only implement interfaces they actually need, avoiding unnecessary dependencies.

Dependency Inversion Principle (DIP)

Definition: 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.

Bad Example:

class MySQLDatabase { public:   void connect() {     cout << "Connecting to MySQL..." << endl;   } }; class UserService { private:   MySQLDatabase database; // Tight coupling public:   void getUser() {     database.connect();     // Get user logic   } };

Good Example:

class Database { public:   virtual void connect() = 0;   virtual ~Database() = default; }; class MySQLDatabase : public Database { public:   void connect() override {     cout << "Connecting to MySQL..." << endl;   } }; class PostgreSQLDatabase : public Database { public:   void connect() override {     cout << "Connecting to PostgreSQL..." << endl;   } }; class UserService { private:   Database\* database; // Depends on abstraction public:   UserService(Database\* db) : database(db) {}       void getUser() {     database->connect();     // Get user logic   } };

ANOTHER EXAMPLE 

using namespace std; class PaymentMethod{       public:         virtual void pay() = 0;    virtual void validate() = 0;        //  virtual ~PaymentMethod() {} ; }; class CardPayment : public PaymentMethod{   private:    int cardNumber;       public:           CardPayment(int cardNumber){       this\->cardNumber = cardNumber;     }           void validate(){       cout<<"validating card payment "<<endl;     }         void pay() override {      cout<<"Payment is Done using card -> "<<cardNumber<<endl;    }     }; class upiPayment : public PaymentMethod{   private:    string upiId;       public:           upiPayment(string upiId){       this\->upiId = upiId;     }           void validate(){       cout<<"validating upi payment "<<endl;     }         void pay() override {      cout<<"Payment is Done using upiId -> "<<upiId<<endl;    }     }; class walletPyment : public PaymentMethod{   private:    int walletId;       public:           walletPyment(int walletId){       this\->walletId = walletId;     }           void validate(){       cout<<"validating wallet payment "<<endl;     }         void pay () override {      cout<<"Payment is Done using wallet -> "<<walletId<<endl;    }     }; class PaymentServices{       private :   PaymentMethod \* pm;       public:        PaymentServices(PaymentMethod \* pm){      this\->pm = pm;    }        //  pm->pay();       void paymentService(){     pm->validate();     pm -> pay();   }         }; int main(){   PaymentMethod \* p1 = new CardPayment(1234);   PaymentMethod \* p2 = new upiPayment("omkar@sbi123");   PaymentMethod \* p3 = new walletPyment(98765);   PaymentServices \* p = new PaymentServices(p1);   PaymentServices \* p4 = new PaymentServices(p2);   PaymentServices \* p5 = new PaymentServices(p3);   p->paymentService();   p4->paymentService();   p5->paymentService();       }

Thanks for Reading... If you like this post hit like and share among friends.

Comments (0)

No comments yet. Be the first to share your thoughts!

Suggested for you

Blog

From the Blog

S.O.L.I.D Principles ( System Design)
Quick Preview

S.O.L.I.D Principles ( System Design)

SOLID is an acronym for five design principles that make software designs more understandable, flexi...

Read Article
Interview Experience (Cognizant GenC)
Quick Preview

Interview Experience (Cognizant GenC)

My Cognizant GenC Next On-Campus Hiring Experience (2025–26 Batch) Recently, I took part in the Cogn...

Read Article
How to Build a Simple To-Do App with HTML, CSS, and JavaScript
Quick Preview

How to Build a Simple To-Do App with HTML, CSS, and JavaScript

How to Build a Simple To-Do App with HTML, CSS, and JavaScript Creating a to-do app is one of the be...

Read Article
Web Developer Roadmap: A Step-by-Step Guide (2025)
Quick Preview

Web Developer Roadmap: A Step-by-Step Guide (2025)

Web Developer Roadmap: A Step-by-Step Guide Web development is one of the most in-demand tech skills...

Read Article