Перейти к содержанию

SOLID Principles

The main purpose of these principles is to increase the flexibility of your architecture, reduce the connectivity between its components and facilitate code reuse.

Warning

Compliance with the SOLID principles usually leads to the complication of the program code.

When there are only 200-300 lines in your application, then the design as such is not needed at all. It is enough to write 5-7 methods carefully, and everything will be fine. Problems arise when the system grows and increases in scale.

Single Responsibility Principle

Single Responsibility Principle

A class should have only one motive for change.

Strive to ensure that each class is responsible for only one part of the functionality of the program, and it should be completely encapsulated in this class (hidden inside the class).

Open/Closed Principle

Open/Closed Principle

Extend classes, but don't change their original code.

Aim for classes to be open for expansion, but closed for change. The main idea of this principle is not to break existing code when making changes to the program.

But do not follow this principle literally for every change. If you need to fix a bug in the original class, just go ahead and do it. It makes no sense to solve the parent problem in a child class.

Liskov Substitution Principle

Liskov substitution principle

In a computer program, if S is a subtype of T, then objects of type T may be replaced with objects of type S without altering any of the desired properties of the program.

Subclasses should complement, not replace, the behavior of the base class.

Formal requirements for methods redefined in subclasses:

  1. The parameter types of the subclass method must match or be more abstract than the parameter types of the base method.
  2. The type of the return value of the subclass method must match or be a subtype of the return value of the base method.
  3. The method should not throw exceptions that are not peculiar to the base method.
  4. The method should not tighten the preconditions.
  5. The method should not weaken the post-conditions.
  6. The invariants of the class should remain unchanged.
  7. The subclass should not change the values of the private fields of the base class.

Interface Segregation Principle

Open/Closed Principle

Clients should not depend on methods that they do not use.

Aim for interfaces to be narrow enough so that classes don't have to implement redundant behavior.

Dependency Inversion Principle

Open/Closed Principle

Upper-level classes should not depend on lower-level classes. Both should depend on abstractions. Abstractions should not depend on details. Details should depend on abstractions.

Usually, when designing programs, two levels of classes can be distinguished:

  1. Lower-level classes implement basic operations like working with a disk, transferring data over a network, connecting to a database, and so on.
  2. High-level classes contain the complex business logic of the program, which relies on low-level classes to perform simpler operations.

Often, you first design the lower-level classes, and only then take on the upper level. With this approach, business logic classes become dependent on more primitive low-level classes. Every change in a low-level class can affect the business logic classes that use it.

The principle of dependency inversion suggests changing the direction in which the design takes place.

  1. First describe the interface of the low-level operations that the business logic class needs.
  2. This will allow you to remove the dependency of the business logic class on a specific low-level class, replacing it with a "soft" dependency on the interface.
  3. The low-level class, in turn, will become dependent on the interface defined by the business logic.