SOLID Design Principles in Software Engineering

AvatarPosted by

What are Design Principles

Design principles are set of guidelines that are used to create a good software systems.

What are SOLID Design Principles

SOLID design principles are one of the most used design principles that have a goal to create robust, extensible, maintainable and testable software systems.

SOLID design principles consist of 5 design principles:

  • Single Responsibility Principle
  • Open – Closed Principle
  • Liskov Substitution Principle
  • Interface Segregation Principle
  • Dependency Inversion Principle

Single Responsibility Principle

The principle states:

Class, module or function should have only one reason to change.

This means that a class, module or function should do only one thing.

Before Implementation

public class Book {
    public String Name { get; set; }
    public String Author { get; set; }
    public String Text { get; set; }

    // methods for outputting text
    void PrintTextToConsole(String text){
        // code for formatting and printing the text
    }

    void PrintTextToAnotherMedium(String text){
        // code for writing to any other location
    }
}

After Implementation

public class Book {
    public String Name { get; set; }
    public String Author { get; set; }
    public String Text { get; set; }
}

public class BookPrinter {

    // methods for outputting text
    void PrintTextToConsole(String text){
        // code for formatting and printing the text
    }

    void PrintTextToAnotherMedium(String text){
        // code for writing to any other location
    }
}

Advantages

  • Reduce the Complexity
  • Enhanced Readability and Maintainability
  • Increased Reusability
  • Easier Testing

Disadvantages

  • Increased Number of Classes

Open – Closed Principle

The principle states:

Classes, modules and functions should be open for extension but closed for modification.

This mean that you should be able to extend functionality of a class, module or function by adding more code without modifying the existing code.

Before Implementation

public class Book {
    public String Name { get; set; }
    public String Author { get; set; }
    public String Text { get; set; }
    public String CoverColor { get; set; }
    public String CoverMaterial { get; set; }
}

After Implementation

public class Book {
    public String Name { get; set; }
    public String Author { get; set; }
    public String Text { get; set; }
}

public class BookWithSpecialCover : Book {
    public String CoverColor;
    public String CoverMaterial;
}

Advantages

  • Maintainability
  • Code Reusability
  • Scalability

Disadvantages

  • Complexity

Liskov Substitution Principle

The principle states:

Derived or child classes should be substitutable for their base or parent classes.

This mean that child classes or subclasses should be substitutable for their parent classes or super classes. In other words child class should be able to replace a parent class.

Before Implementation

static void Main(string[] args)
{
    Apple apple = new Orange();
    Console.WriteLine($"Color of Apple: {apple.GetColor()}"); // Color of Apple: Orange - Which is wrong
}

public class Apple
{
    public virtual string GetColor()
    {
        return "Red";
    }
}

public class Orange : Apple
{
    public override string GetColor()
    {
        return "Orange";
    }
}

After Implementation

static void Main(string[] args)
{
    IFruit fruit = new Orange();
    Console.WriteLine($"Color of Orange: {fruit.GetColor()}"); // Color of Orange: Orange - Which is correct
    fruit = new Apple();
    Console.WriteLine($"Color of Apple: {fruit.GetColor()}"); // Color of Apple: Red - Which is correct
}

public interface IFruit
{
    string GetColor();
}

public class Apple : IFruit
{
    public string GetColor()
    {
        return "Red";
    }
}

public class Orange : IFruit
{
    public string GetColor()
    {
        return "Orange";
    }
}

Advantages

  • Code Reusability
  • Flexibility 
  • Extensibility

Disadvantages

  • Complexity 
  • Design Challenges

Interface Segregation Principle

The principle states:

Clients should not be forced to implement interfaces or methods they do not use.

This mean that larger interfaces should be split into smaller ones. By doing this, clients will not implement methods that are not necessary.

Before Implementation

public interface IDocument
{
    void Open();
    void Edit();
    void Save();
    void Print();
}

public class PDFDocument : IDocument
{
    public void Open() { /* PDF open logic */ }
    public void Edit()
    {    
        throw new NotImplementedException("Editing is not applicable for PDF");
    }
    public void Save() { /* PDF save logic */ }
    public void Print() { /* PDF print logic */ }
}

public class WordDocument : IDocument
{
    public void Open() { /* Word open logic */ }
    public void Edit() { /* Word edit logic */ }
    public void Save() { /* Word save logic */ }
    public void Print() { /* Word print logic */ }
}

After Implementation

public interface IDocument
{
    void Open();
    void Save();
}
public interface IEditableDocument
{
    void Edit();
}

public interface IPrintableDocument
{
    void Print();
}

public class PDFDocument : IDocument, IPrintableDocument
{
   public void Open()
    {
        Console.WriteLine("Opening PDF document"); /* PDF open logic */
    }

    public void Save()
    {
        Console.WriteLine("Saving PDF document"); /* PDF save logic */ 
    }

    public void Print()
    {
        Console.WriteLine("Printing PDF document"); /* PDF print logic */
    }
}

public class WordDocument : IDocument, IEditableDocument, IPrintableDocument
{
   public void Open()
    {
        Console.WriteLine("Opening Word document");  /* Word open logic */ 
    }

    public void Edit()
    {
        Console.WriteLine("Editing Word document"); /* Word edit logic */
    }

    public void Save()
    {
        Console.WriteLine("Saving Word document"); /* Word save logic */
    }

    public void Print()
    {
        Console.WriteLine("Printing Word document"); /* Word print logic */ 
    }
}

Advantages

  • Reduced Coupling
  • Improved Maintainability
  • Flexibility in Implementations
  • Enhanced Reusability

Disadvantages

  • Complexity

Dependency Inversion Principle

The principle states:

High-level modules/classes should not depend on low-level modules/classes. Both should depend upon abstraction.

Abstractions should not depend upon details. Details should depend upon abstractions.

This mean that modules/classes should be decoupled of each other.

Before Implementation

public class Student
{
    public int StudentId { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public DateTime DoB { get; set; }

    // tight coupling - which is a problem
    private StudentRepository _stdRepo = new StudentRepository();
       
    public Student() { }

    public void Save()
    {
        _stdRepo.AddStudent(this);
    }
}

public class StudentRepository 
{
    public void AddStudent(Student std)
    {
        // Code for adding new student
    }

    public void DeleteStudent(Student std)
    {
        // Code for deleting student
    }

    public void EditStudent(Student std)
    {
        // Code for editing student
    }
        
    public IList<Student> GetAllStudents()
    {
        // Code for getting all students
    }
}

After Implementation

public class Student
{
    public int StudentId { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public DateTime DoB { get; set; }

    private IStudentRepository _stdRepo;

    public Student(IStudentRepository stdRepo)
    {
        _stdRepo = stdRepo;
    }

    public void Save()
    {
        _stdRepo.AddStudent(this);
    }
}

public interface IStudentRepository
{
    void AddStudent(Student std);
    void EditStudent(Student std);
    void DeleteStudent(Student std);
        
    IList<Student> GetAllStudents();
}

public class StudentRepository : IStudentRepository
{
    public void AddStudent(Student std)
    {
        // Code for adding new student
    }

    public void DeleteStudent(Student std)
    {
        // Code for deleting student
    }

    public void EditStudent(Student std)
    {
        // Code for editing student
    }

    public IList<Student> GetAllStudents()
    {
        // Code for getting all students
    }
}

Advantages

  • Loose Coupling
  • Flexibility 
  • Extensibility
  • Testability
  • Parallel Development

Disadvantages

  • Complexity 
SOLID Design Principles

Thanks for reading this post.

References

  1. Millington, W. by: S. (2022) A solid guide to solid principles, Baeldung. Available at: https://www.baeldung.com/solid-principles (Accessed: 03 September 2023).
  2. 4, P.V.S. et al. (2023) Single responsibility principle in C#, Dot Net Tutorials. Available at: https://dotnettutorials.net/lesson/single-responsibility-principle/ (Accessed: 03 September 2023).
  3. 12, K., 4, S., et al. (2023) Open-closed principle in C#, Dot Net Tutorials. Available at: https://dotnettutorials.net/lesson/open-closed-principle/ (Accessed: 03 September 2023).
  4. 12, K. et al. (2023) Liskov substitution principle in C#, Dot Net Tutorials. Available at: https://dotnettutorials.net/lesson/liskov-substitution-principle/ (Accessed: 03 September 2023).
  5. 12, K., 3, V., et al. (2023) Interface segregation principle in C#, Dot Net Tutorials. Available at: https://dotnettutorials.net/lesson/interface-segregation-principle/ (Accessed: 03 September 2023).
  6. 12, K. et al. (2023) Dependency inversion principle in C#, Dot Net Tutorials. Available at: https://dotnettutorials.net/lesson/dependency-inversion-principle/ (Accessed: 03 September 2023).
  7. Ali, S. and Ali, S.A.S. (2023) Understanding the C# interface segregation principle (ISP) with examples, Shekh Ali’s Blog. Available at: https://www.shekhali.com/csharp-interface-segregation-principle/ (Accessed: 03 September 2023).
  8. Solid: Dependency inversion principle (no date) TutorialsTeacher. Available at: https://www.tutorialsteacher.com/csharp/dependency-inversion-principle (Accessed: 03 September 2023).
  9. Single responsibility in solid design principle (2022) GeeksforGeeks. Available at: https://www.geeksforgeeks.org/single-responsibility-in-solid-design-principle/ (Accessed: 04 September 2023).

Leave a Reply

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