SOLID contains five design principles that are used to make it easier to understand software designs.
Any class should only have a single responsibility, i.e. the
class should have only a single job/task. In simple terms, if you have a Vehicle class that process any number of vehicle objects. If the processed
vehicle objects need to be stored or serialised, both the storage and serialisation tasks can easily be added to the class, but they shouldn’t.
Only changes to one part of the software’s specification should be able to affect the specification of the class, so what if the storage type changes from a database to blob or table storage or the serialisation changes from say XML to JSON? You’d be violating the Single Resposibility principle, but creating a new class for either or both of these tasks and let them handle the storage or serialisation tasks, will work without violating this principle.
Any software entity, class, should be open for extension, but closed for modification, i.e. the class should be easily extendable, but without modifying the existing class. In simple terms, if you have a Vehicle class that process any number of different vehicle objects Car, Van, Bus etc. For each processed vehicle object , the exhaust emission must be calculated. Assume that the calculation is different for each vehicle type. The class method that does the calculation must check each vehicle object for the actual type, and base the calculation on that. Now, if all types of vehicles are known at the time of the Vehicle class being written, no problem. However, in reality new types of vehicles are introduced frequently, so the calculation method is violating the Open Closed principle, because adding calculation for new vehicle types, requires the calculation method to be modified. To address this, each vehicle type class must come with their own calculation method. This way, when you’re creating a new type of vehicle class, and assuming you’re inheriting from the same abstract class or interface, you’re extending the Vehicle class, not modifying it.
Objects in an application should be replaceable with instances of their subtypes without altering the correctness of the application. If you have a class Vehicle, and any number of subtypes thereof, say Car, Bicycle, Bus, you hould to replace super class with any of the subtypes. Typically Inversion of Control (IoC) or Dependency Injection (DI) is used to inject the super type or any of the subtypes into a class Controller. You need to ensure that the injected objects do not alter how the Controller process and output results.