- SOLID is an acronym for the five basic principles of object-oriented programming and design.
- They make it more likely that a programmer will create a system that is easy to maintain and extend over time.
- They can be applied while working on software to remove code smells.
- Programmer refactors the code until it is both legible and extensible.
- SOLID is part of an overall strategy of agile and adaptive programming.
Single Responsibility Principle (SRP)
- A class should have only a single responsibility (or one reason to change).
- E.g. only one change in the specification should be able to affect the specification of the class.
- Too many responsibilities increase the odds of introducing bugs.
- It also makes it difficult to unit test the class logic.
Open/Closed Principle
- Software entities should be open for extension but closed for modification.
- Closed for modification: Extending the behavior of a module does not result in changes to the source of the module.
- In a nutshell, being closed for modification means you shouldn’t change the behavior of the existing code.
- There are, however, three ways you could change the behavior of existing code:
- The first is to fix a bug.
- After all, the code is not functioning properly and should be fixed.
- You need to be careful here as clients of the class may know about this bug and have taken steps to get around this.
- The second reason to modify existing code is to refactor the code so that it follows the other SOLID principles.
- For example, the code may be working perfectly but does too much, so you wish to refactor it to follow Single Responsibility.
- A third way, which is somewhat controversial, is you are allowed to change the code if it doesn’t change the need for clients to change.
- You have to be careful here so that you don’t introduce bugs that affect the client.
- Open for extension: This means that the behavior of the module can be extended.
- As the requirements of the application change, we are able to extend the module with new behaviors that satisfy those changes.
- This approached can be implemented using inheritance, interface implementation, and abstract methods.
- There is one other to provide additional functionality and it is the extension methods.
- While they don't change the behavior of a method, it does allow you extend the functionality without changing the original class code.
Liskov Substitution Principle (LSP)
- Given a specific base class, any class that inherits from it, can be a substitute for the base class.
- In fact, objects in a program should be replaceable with instances of their sub-types without altering the correctness of that program.
LSP Contract Rules
- The class contract states the formal terms of how to use the object.
- These terms are the name of the methods, their parameters, data types of those parameters, and the data type of the return value.
- Preconditions cannot be strengthened by the sub-type:
- Preconditions are the things required by the method to run reliably.
- This would require the class to get instantiated correctly and required parameters are passed to the method.
- Typically, guard clauses are used to enforce that parameters are of the correct values.
- Post-conditions cannot be weakened in the sub-type:
- Post-conditions verify the object is left in a reliable state when the method returns.
- Guard clauses are again used to enforce post-conditions.
- Invariants of the super-type must be preserved by the sub-type:
- Invariants are things that must remain true during the lifetime of the object once object construction is finished.
- This could be a field value that gets set in the constructor and is assumed to not change.
- The subtype should not change these type of fields to invalid values.
- For example, there may be a business rule that minimum shipping charge field must be greater than or equal to zero.
- The subtype should not make it negative.
- Read-only fields guarantee this rule is followed.