SOLID Principles
S: Single responsibility.
A class or a method, there is only one reason to change it.
In simple terms, the Single Responsibility Principle states that a class or method should be designed to serve a single, well-defined functionality. This makes it easier to test and maintain, as each class or method is focused on a specific responsibility and can be tested in isolation.
In coding practices, it's essential to separate responsibilities during system design.
For example, when you need to instantiate an HTTP client, consider creating a Factory Class solely dedicated to producing HttpClient instances. In this design approach, another class, named ClientConfiguration, would be responsible only for gathering and storing all client configuration parameters. This configuration would then be passed as an input argument to the Factory.
O: Open-Close principle.
Objects or entities open for extension but close for modification.
Once a class and its methods have been implemented and tested, especially already in production, then modifying its code may lead to side effects. So it is considered to be closed to make code changes to it.
So making a new behaviours based on an existing Java class, maybe by extending and overriding the existing method, or by decorating the existing one with a wrapper. They are using the same principle extension and then overriding the parent behaviour, and thus without modifying the existing behaviour, it gives a new behaviour based on the legacy class.
L: Liskov Substitution Principle(Barara Liskov)
From the O: principle, we may already know, we probably need this L: principle. All subtypes of a A class, may substitute A, and won't disrupt the current system behaviours.
I: Interface Segregation principle.
The reason why we need to segregate interfaces according to different usage perspectives is to avoid forcing clients to depend on interfaces that they do not use. By designing interfaces that are specific to the needs of the clients, we can ensure that clients only depend on the interfaces that they actually need, which promotes flexibility, modularity, and maintainability in the codebase.
D: Dependency Inversion Principle.
By depending on abstractions rather than concrete implementations, strong connections between modules or layers can be decoupled. This allows for the replacement of the concrete implementation of dependent abstractions without disrupting upper layers(modifying its code), and also upper layer classes become reusable for removing dependency on a concrete implementation. The purpose to decouple classes is to achieve independence and set up a clear boundary between classes. In this way, it may be reused to handle the same problem in different contexts, so it is a way to DRY code in coding practice.