November 24, 2020
Object Oriented Analysis design ooad

SOLID Principles: Explanation and examples

SOLID is the short form of 5 important design principles when doing OOD. It helps to make software designs more understandable, easier to maintain and easier to extend. As an ideal software engineer, these 5 principles are essential to know.

SOLID Principles
SOLID stands for:

  • S -Single Responsibility Principle (SRP)
  • O -Open Closed Principle (OCP)
  • L -Liskov Substitution Principle (LSP)
  • I -Interface Segregation Principle (ISP)
  • D -Dependency Inversion Principle (DIP)

Single Responsibility Principle (SRP)
This principle states that software entities (classes, modules, functions, etc.) will perform only one job.

class Customer
 {
    void CreateCustomer(Database db, string custMessage)
    {
        try
        {
            db.Add(custMessage);
        }
        catch (Exception ex)
        {
            db.LogError("An error occured: ", ex.ToString());
            File.WriteAllText("\LocalErrors.txt", ex.ToString());
        }
    }
 }

Note that, here CreateCustomer() method has too much responsibility. It create new customer, saver error in the database, write error log in a file. This violates the single responsibility principle. Let’s correct it.

class Customer
 {
    private ErrorLog errorLog = new ErrorLog();

    void CreateCustomer(Database db, string custMessage)
    {
        try
        {
            db.Add(custMessage);
        }
        catch (Exception ex)
        {
            errorLog.log(ex.ToString())
        }
    }
 }
class ErrorLog
 {
    void log(string error)
    {
      db.LogError("An error occured: ", error);
      File.WriteAllText("\LocalErrors.txt", error);
    }
 }

Now we have two classes that each has one responsibly/job.

Open Closed Principle (OCP)
This principle states that software entities (classes, modules, functions, etc.) should be open for extensions, but closed for modification. That means, we have to compose our class in such a way that, we can reuse it without any modification.

class Customer
 {
    void CreateCustomer(Database db, string custMessage)
    {
        if (custMessage.StartsWith("#"))
        {
            db.AddAsTag(custMessage);
        }
        else
        {
            db.Add(custMessage);
        }
    }
 }

Here, we need to start a tag with the character “#”. If we want to use “@” or others character we have to modify our code. This is a violation of open close principal. To overcome this we have to modify our codes.

class Customer
 {
    void CreateCustomer(Database db, string custMessage)
    {
        db.Add(custMessage);
    }
 }

class TagCustomer : Customer
 {
    override void CreateCustomer(Database db, string custMessage)
    {
        db.AddAsTag(custMessage);
    }
 }

Liskov Substitution Principle (LSP)
This principles states that if A is a subtype of B, then objects of type B may be replaced (or substituted) with objects of type A

Interface Segregation Principle (ISP)
This principal states that do not add additional functionality to an existing interface by adding new methods. Instead of that, create a new interface and let your class implement multiple interfaces if needed.

interface ICustomer
 {
    void CreateCustomer();
 }

interface ICustomerNew
 {
    void CreateCustomer();
    void ReadCustomer();
 }

In the above code we violate the interface segregation principle. To overcome this we need to modify our codes.

interface ICustomerCreate
 {
    void CreateCustomer();
 }

interface ICustomerRead
 {
    void ReadCustomer();
 }

Dependency Inversion Principle (DIP)
This principal states that 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. We can solved this by using dependency injection.

class Customer
 {
    private ErrorLog errorLog = new ErrorLog();

    void CreateCustomer(Database db, string custMessage)
    {
        try
        {
            db.Add(custMessage);
        }
        catch (Exception ex)
        {
            errorLog.log(ex.ToString())
        }
    }
}

Here we create ErrorLog  instance inside the Customer class. This is a violation of the dependency inversion principle. To overcome it, we need to modify our code.

class Customer
 {
    private ErrorLog _errorLog ;

    public Customer(ErrorLog errorLog )
    {
        _errorLog = errorLog ;
    }

    void CreateCustomer(Database db, string custMessage)
    {
        try
        {
            db.Add(custMessage);
        }
        catch (Exception ex)
        {
            _errorLog.log(ex.ToString())
        }
    }
}

By using dependency injection we no longer rely on the Customer class to define the specific type of ErrorLog.

This 5 solid principles are very essential and used by the software engineers all around the world. By applying these you can make a reusable, maintainable, scalable code. We should try to apply these.

Rashedul Alam

I am a software engineer/architect, technology enthusiast, technology coach, blogger, travel photographer. I like to share my knowledge and technical stuff with others.

View all posts by Rashedul Alam →

One thought on “SOLID Principles: Explanation and examples

Leave a Reply

Your email address will not be published. Required fields are marked *