The SOLID principles are comprised of five individual principles for writing better software, especially in object-oriented languages. Let’s see one by one:
1. Single Responsibility Principle:
Class should have one, and only one, reason to change.
What is responsibility exactly means? : It’s a decision our code is making about the specific implementation details of some part of what the application does. Responsibilities in our code represent things that may change at different times and for different reasons. This is closely related to following points:
- Loose Coupling: Loose coupling refers to approaches that can be used to support having different details of the application interact with one another in a modular fashion.
- Separation of concerns: suggests that programs should be separated into distinct sections that each address a separate concern or set of information that affects the program.
- Cohesion: describes how closely related elements of a class or module are to one another. Classes that have many responsibilities will tend to have less cohesion than classes that have a single responsibility.
2. Open-Closed Principle:
OCP says that software entities like classes, modules, functions, and so on, should be open for extension but closed for modification. What is that mean?
Typical Approaches to OCP:
- Use Parameters: By passing in different arguments to a function or method, we can change its behavior.
- Use Inheritance: By using Inheritance we can change the behavior of the underlying type without having to change or even have access to that type simply by creating a new child class that inherits from it.
- Using composition and injection: Instead of placing logic directly within a class, the logic is provided by another type the class references.
3. Liskov Substitution Principle:
Derived classes must be substitutable for their base classes. If any module is using a Base class then the reference to that Base class can be replaced with a Derived class without affecting the functionality of the module.
Fixing LSP Violations:
- Follow the “Tell, Don’t Ask” principle. Don’t ask instances for their type and then conditionally perform different actions, but instead encapsulate that logic in the type itself, and tell it to perform an action.
- Minimise the Null checks of object with new features of C#
- Use Guard Clauses to check Nulls
- Whenever implement an interface or inherit from a base class, make sure you fully implement it.
4. Interface Segregation Principle:
The Interface Segregation Principle states that client should not be forced to depend on methods they do not use. Interface Segregation violations result in the classes that depends upon they don’t need, increasing coupling, reducing flexibility and maintainable.
- ISP is related to Liskov substitution principle. Large interfaces are harder to fully implement and, thus, more likely to only be partially implemented and, therefore, to not be substitutable for their base type.
- The interface segregation principle also relies heavily on cohesion. Small, cohesive interfaces are preferable to large interfaces whose methods are only loosely related to one another.
Fixing ISP Violations:
- Breaking larger interfaces to smaller interfaces
- Use Adaptor Design Pattern to create small, cohesive interfaces
5. Dependency Inversion Principle:
High-Level modules should not depend upon low-level modules. Both should depend upon abstractions. Abstractions should not depend upon details. Details should depend upon abstractions.
Dependancy Injection is technique that is used to allow calling code to inject the dependancies a class needs when it is instantiated. Three Primary Principles:
- Constructor Injection
- Property Injection
- Parameter Injection
Advantages of Dependency Injection :
- Late Binding
- Parallel Development