SOLID is an acronym of below five object-oriented design principles.

  • S – Single Responsibility
  • O – Open Closed
  • L – Liskov Substitution
  • I – Interface Segregation
  • D – Dependency Inversion

Single Responsibility Principle

Every entity (class, method, or module) should have a single responsibility. In other words, every entity must have a single reason to change.

Open Closed Principle

Every class should be Open for extension and Closed for modification.

For example, if there is a method to read a file and the filename is hardcoded in the function, we need to change the method whenever the file name changes. Instead of hardcoding the filename, we can pass it via a parameter in the method.

However, there is an exception to fixing bugs in the code.

Liskov Substitution

In simple words, it is to replace the supertype object with the subtype object and the behaviour is not undesirable then this test has been passed.

If S is a subclass of T, then the object of T can be replaced with the object of S without getting any undesirable behaviour.

For example, if we create a class Rectangle with properties width and height then we create its subclass Square which sets the width and height the same whenever we update any of them. When we added the constraint in the square, it leads to undesirable behaviour when we substitute the square object for the rectangle object. In this example, it did not pass.

class Rectangle {
	Integer width;
	Integer height;

class Square extends Rectangle {
	public void setWidth(Integer width){
		this.width = width;
		this.height = width;
	public void setHeight(Integer height){
		this.width = height;
		this.height = height;

Let's create a Rectangle object (supertype)
Rectangle r = new Rectangle();
Now checking Liskov Substitution by replacing Rectangle object with the Square object.
The square objects ensures the constraint that width and height must be same. 
However the reference type is rectangle. Hence, the liskov substitution test has not passed.

Rectangle r = new Square();

Interface Segregation

An interface should only have those methods which can be implemented by any client. In other words, no client should be forced to implement methods that it does not use. If that’s the case, we should divide the interface into two or more interfaces so that every client implements only those methods that it’s using.

Dependency Inversion

Whenever we have a dependency on objects, they should be passed via the constructor. We should not create the objects and make the class tightly coupled with the objects. High-level modules should not depend on the low-level modules, instead, they should rely on abstractions.

It also helps in unit testing. We can mock the dependencies by providing their mocks.

Leave a Reply

Your email address will not be published.