Mastering Software Design Principles and SOLID Patterns
Classified in Computers
Written on in
English with a size of 206.57 KB
Core Software Design Principles
- Abstraction: Removal or masking of detail and complexity.
- Modularity: Software is divided into separately named and addressable components.
- Separation of Concerns: Any complex problem can be more easily handled if it is subdivided into pieces.
- Information Hiding / Encapsulation: Hide implementation details from client components; communicate only via controlled interfaces.
- High Cohesion: Components provide specific functionality.
- Low Coupling: Components have as few dependencies as possible so they can change with minimal impact on other components.
SOLID Principles
Single Responsibility Principle
The idea here is simple: Separate the code that supports different actors (i.e., users, stakeholders, or client components). The component must perform a single specific task relevant to the use case of one stakeholder.
The goal is that the component must change only as a result of its related actor. There should be no reason for any other actor to request a modification to the component.
- Each class has one responsibility:
- PrintingStrategy class to print.
- SalesDataFixed class to hold the data.
Open/Closed Principle
Open for Extension, Closed for Modification.
If you want to extend the behavior of a software component, you add new parts to it and modify as little as possible (ideally nothing at all) of its existing parts. In well-designed classes, adding new methods should not require modifying existing ones.
This prevents us from modifying existing code and causing potential new bugs in a stable application. Typical separation of responsibilities:
- SalesData: The Model (holds the data). It has a reference to the IPrinter (the Viewer).
- IPrinter: The Viewer (responsible for doing something with the data).
- DataController: The Controller (alters the data). It has a reference to the SalesData (the Model).
- BusinessLogicUtilities: Holds the business logic (e.g., calculate min, max, average).
Liskov Substitution Principle
If I substitute component C1 for another component C2 and I want the behavior of the system to be the same, then C2 must be a subtype of C1.
- If you have two classes, C2 and C3, which inherit from C1:
- Any component D that references C1 can substitute it with C2 or C3 without changing its behavior.
- Any methods of C1 inherited by C2 and C3 and used by D can still be used by D when C1 is substituted.
The moral: Avoid overwriting inherited methods. If you need to alter an inherited method in a subclass, consider a new method or the use of an interface class (e.g., flying and swimming duck).
Interface Segregation Principle
Inherit only the functionality one needs to use. Conversely, do not have components inherit functionality they do not need.
For example, if an interface I specifies three operations (op1, op2, op3) and two classes (C1 and C2) implement it, but only C1 uses all three while C2 uses only op1, we practically force C2 to implement two dummy methods that do nothing.