Skip to content

SOLID Principles

Vanskarner edited this page Jul 26, 2023 · 5 revisions

They are code-level design guidelines for writing software that promote modularity, extensibility and maintainability. Although they are code-level principles, they have a strong influence on component principles, so their concepts reflect that as well.

There are 5 principles:

Single Responsibility Principle

It establishes that each class, module or software component must have a single clear and specific responsibility, which implies that it must not have additional dependencies or responsibilities that are not related to its main purpose.

Incorrect Example Correct Example
S-Incorrect S-Correct
The Worker class defines the methods generateReport() and calculateSalary(), which provide more than one responsibility and are not directly related to its main purpose. To comply with this principle, the ReportGenerator and CompensationCalculator classes were delegated responsibility for handling these methods. Now each class has a single clear and specific responsibility.

Open-Closed Principle

It aims at extending behavior in an easy way, without having a high impact in the face of change or without modifying the existing code.

Incorrect Example Correct Example
O-Incorrect O-Correct
The Specification class defines the attributes and methods for each iPhone model. The problem arises if new specifications different from the established ones are required, since it would imply modifying the code, violating the principle. To comply with this principle, the Model interface has been created. Then, each time a new model appears, you only have to implement it from the Model interface, as seen in the Plus and Pro models.

Liskov’s Substitution Principle

The aim of the principle is to ensure that a subclass can be used as its superclass without generating undesirable effects or errors in the program behavior.

Incorrect Example Correct Example
L-Incorrect L-Correct
We have the representation of birds and their most common methods. The behavior of the fly() method is expected in birds such as Pigeon and Crow, but is unexpected in the case of Penguin, since it should not have such a method implemented. This violates the principle, since the subclass (Penguin) cannot be used as its superclass (Bird). To comply with this principle, the FlyingBird interface has been added which contains the fly() method and now only birds that have the ability to fly would implement this interface, on the other hand, the Penguin class would only implement of Bird

Interface Segregation Principle

This principle establishes that interfaces must be specific and consistent for each client, avoiding the inclusion of unnecessary or confusing functionalities.

Incorrect Example Correct Example
I-Incorrect I-Correct
We have the Repository interface and two classes that implement it; however, the getRemoteItems() method is not used in LocalRepository and the getLocalItems() method is not used in RemoteRepository. This indicates a non-compliance with this principle. To fulfill this principle, it is necessary to create another interface to better divide the functionalities for each implementation. We now have the LocalRepository and RemoteRepository interface, along with their respective implementations, where the methods are specific and consistent.

Dependency Inversion Principle

This principle states that high-level policies should not depend directly on low-level details, but on abstractions.

Incorrect Example Correct Example
D-Incorrect D-Correct
The use case calls CustomRemoteRepository directly, which implies that it is aware of the implementation details of that class, such as the use of frameworks or libraries to carry out its functions. This violates the principle. To fulfill this principle, we use a RemoteRepository interface as an abstraction to avoid relying on implementation-specific details. Now it is the details, such as CustomRemoteRepository, that depend on the high-level policy.
Clone this wiki locally