SOLID Principles in Software Development

Shehani Fernando
6 min readFeb 26, 2021

--

SOLID is a mnemonic acronyms which are used in OOP when developing the Software tools. It was first introduced in 2000 by an American Software Engineer named as Robert Cecil Martin (called as “Uncle Bob”). The broad goal of the SOLID principles is to reduce dependencies so that engineers change one area of software without impacting others. Additionally, the intention of these principles is to make the software designs more understandable, easier to maintain and extend.

Robert C. Martin

The 5 Solid Principles are:

· Single Responsibility Principle

· Open-Closed Principle

· Liskov Substitution Principle

· Interface Segregation Principle

· Dependency Inversion Principle

S.O.L.I.D Principles of OOP Design

SOLID #1: Single Responsibility Principle

“A class should have one and only one reason to change”

(Which means a class should have only one responsibility)

BENEFITS!

  1. Testing
  2. Lower coupling
  3. Organization

EXAMPLE!

Let’s consider a simple Student class:

Suppose, Student is a class having three methods namely printDetails(), calculatePercentage(), and addStudent(). Hence, the Student class will have three responsibilities which are, to print the student details, calculate the percentages, and database area. By using the single responsibility principle, we can easily fulfill the goal of the principle by separating these functionalities into three separate classes.

Student.java

The above code snippet violates the Single responsibility principle. Therefore to achieve the goal of the principle, we should implement a separate class that performs a single functionality only as below;

Student.java
PrintStudentDetails.java
Percentage.java

Hence, in this way we can achieve the goal of Single responsibility principle by separating the functionality into three separate classes.

SOLID #2: Open-Closed Principle

“Software entities (classes, modules, functions, etc.) should be open for extension, but closed for modification”

(The extension allows us to implement new functionality to the module)

BENEFITS!

  1. Maintainable and reusable
  2. More robust

EXAMPLE!

Let’s consider a simple VehicleInfo class:

Suppose, VehicleInfo is a class and it has the method vehicleNumber() which returns the vehicle number.

VehicleInfo.java

If we want to add another subclass named Truck, simply, we add one more if statement which violates the Open-closed principle. The only way to add the subclass and achieve the goal of principle is by overriding the vehicleNumber() method, as shown below;

VehicleInfo.java

Similarly, we can add more vehicles by making another subclass extending from the vehicle class without modifying it. In this way, the approach would not affect the existing application.

SOLID #3: Liskov Substitution Principle

“Child classes should never break the parent class’ type definitions.”

(If class A is a subtype of class B, then we should be able to replace B with A without interrupting the behavior of the program)

This is the most complex principle and was defined by Barbara Liskov.

BENIFITS!
1. Code is more reusable

2. Class hierarchies are easy to understand

EXAMPLE!

Student.java

The above classes violated the Liskov substitution principle because the StudentBMI class has extra constraints i.e. height and weight that must be the same. Therefore, the Student class (base class) cannot be replaced by StudentBMI class (derived class).

Hence, substituting the class Student with StudentBMI class may result in unexpected behavior.

SOLID #4: Interface Segregation Principle

“The interface-segregation principle (ISP) states that no client should be forced to depend on methods it does not use.”

The principle states that the larger interfaces split into smaller ones. Because the implementation classes use only the methods that are required. We should not force the client to use the methods that they do not want to use.

The goal of the interface segregation principle is similar to the single responsibility principle. Let’s understand the principle through an example.

BENEFITS!

  1. Decoupled system
  2. Code easy to refactor

EXAMPLE!

Suppose, we have created an interface named Conversion having three methods intToDouble(), intToChar(), and charToString().

The above interface has three methods. If we want to use only one method intToChar(), we have no choice to implement the single method. To overcome the problem, the principle allows us to split the interface into three separate ones as below;

Now we can use only the method that is required. Suppose, we want to convert the integer to double and character to string then, we will use only the methods intToDouble() and charToString() as below;

SOLID #5: Dependency Inversion Principle

“High-level modules should not depend on low-level modules. Both should depend on abstractions.
Abstractions should not depend upon details. Details should depend upon abstractions.”

BENEFITS!

  1. Reduce the coupling
  2. Code more reusable

EXAMPLE!

It is worth, if we do not have the keyboard and the mouse to work on Windows. To solve this problem, we create a constructor of the class and add the instances of the keyboard and monitor. After adding the instances, the class looks like the following:

Now we can work on the Windows machine with the help of a keyboard and a mouse. But we still face the problem. Because we have tightly coupled the three classes together by using the new keyword. It is hard o test the class windows machine.

To make the code loosely coupled, we decouple the WindowsMachine from the keyboard by using the Keyboard interface and this keyword as below;

Keyboard.java
WindowsMachine.java

In the above code, we have used the dependency injection to add the keyboard dependency in the WindowsMachine class. Therefore, we have decoupled the classes.

Why should we use SOLID principles?

  • It reduces the dependencies so that a block of code can be changed without affecting the other code blocks.
  • The principles intended to make design easier, understandable.
  • By using the principles, the system is maintainable, testable, scalable, and reusable.
  • It avoids the bad design of the software.

Next time when you design software, keeps these five principles in mind. By applying these principles, the code will be much more clear, testable, and expendable!

--

--