Design principles SOLID

Design principles provide high level guidelines to design better software applications. They do not provide implementation guidelines and are not bound to any programming language.

S.O.L.I.D is an acronym for the first five object-oriented principles by Robert C. Martin, popularly known as Uncle Bob.

single-responsibility principle (SRP)

Class should have only one responsibility. And class should have only one reason for change. What is responsibility? Any job like describing real world objects, implementing some data structure, performing some big task.

For example, let's we have shapes classes like Rectangle and Circle. And we need to export the shapes to xml format. If we implement this feature inside shapes, this will violates the SRP principle because we will have more than one reason to change these classes in future:

  • add a specific attribute to shape
  • XML structure can change
  • XML can change to JSON or something else

Obviously, only first reason is related to the shape itself. And it would be better to implement export in a separate class.

open-closed principle (OCP)

Objects or entities should be open for extension, but closed for modification. With extending we can be sure that our existing application won't be affected.

This does not mean that anybody can change the whole logic of the class, but one should be able to override some options in a non harmful way.

Liskov Substitution (LSP)

Derived classes must be substitutable for their base classes. In other words, a subclass should override the parent class methods in a way that does not break functionality from a client’s point of view.

interface segregation principle (ISP)

A client should never be forced to implement an interface that it doesn't use or clients shouldn't be forced to depend on methods they do not use.

dependency inversion principle (DIP)

Entities must depend on abstractions not on concretions. The high level module must not depend on the low level module, but they should depend on abstractions.

Let's we have application. And we need to embed a logging system, that prints messages to the console. We can use ConsoleLogger with method print() directly everywhere in application. But if we decide to change the logging system to FileLogger with method out() in the future, we need to refactor all the code. So it's better to make an abstract Logger interface and work with any logger system through this interface.