You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Readability improvements
Removed a few areas of clutter
Added spacing
removed Headers from the listing.
Added a note for an important section.
Added " Example " text and modifications for code block areas.
Copy file name to clipboardExpand all lines: docs/Concepts/SOLID.md
+44-26Lines changed: 44 additions & 26 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -11,36 +11,51 @@ has_children: false
11
11
12
12
## What is SOLID?
13
13
Not just a state of matter!
14
-
SOLID is an acronym that represents a set of principles for writing maintainable and scalable object-oriented code. These principles were introduced by Robert C. Martin, and are considered fundamental guidelines for software development. Each letter in SOLID represents a different principle.
14
+
SOLID is an acronym that represents a set of principles for writing maintainable and scalable object-oriented code. These principles were introduced by Robert C. Martin, and are considered fundamental guidelines for software development.
15
15
16
-
### 1) S = Single Responsibility Principle (SRP):
17
-
- A class should have only one reason to change, meaning it should have only one responsibility or job.
18
-
- This principle encourages the organization of code by ensuring that each class or module has a clear and specific purpose.
16
+
---
17
+
18
+
### Each letter in SOLID represents a different principle:
19
+
20
+
<br>
21
+
22
+
1.**S = Single Responsibility Principle (SRP):**
23
+
24
+
- A class should have only one reason to change, meaning it should have only one responsibility or job.
25
+
- This principle encourages the organization of code by ensuring that each class or module has a clear and specific purpose.
19
26
20
-
### 2) O = Open/Closed Principle (OCP):
21
-
- Software entities (classes, modules, functions, etc.) should be open for extension but closed for modification.
22
-
- This means that you should be able to add new functionality without altering existing code.
27
+
2.**O = Open/Closed Principle (OCP):**
23
28
24
-
### 3) L = Liskov Substitution Principle (LSP):
25
-
- Subtypes should be substitutable for their base types without altering the correctness of the program.
26
-
- In simpler terms, objects of a superclass should be replaceable with objects of a subclass without affecting the functionality of the program.
29
+
- Software entities (classes, modules, functions, etc.) should be open for extension but closed for modification.
30
+
- This means that you should be able to add new functionality without altering existing code.
27
31
28
-
### 4) I = Interface Segregation Principle (ISP):
29
-
- Clients should not be forced to depend on interfaces they do not use.
30
-
- This principle suggests that it is better to have small, specific interfaces rather than a large, all-encompassing one. Clients should not be forced to implement interfaces they don't need.
32
+
3.**L = Liskov Substitution Principle (LSP):**
31
33
32
-
### 5) D = Dependency Inversion Principle (DIP):
33
-
- High-level modules should not depend on low-level modules; both should depend on abstractions. Additionally, abstractions should not depend on details; details should depend on abstractions.
34
-
- This principle encourages the use of abstractions (such as interfaces or abstract classes) to decouple high-level modules from low-level modules, promoting flexibility and maintainability.
34
+
- Subtypes should be substitutable for their base types without altering the correctness of the program.
35
+
- In simpler terms, objects of a superclass should be replaceable with objects of a subclass without affecting the functionality of the program.
35
36
36
-
Applying SOLID principles in your code can lead to a more modular, flexible, and maintainable codebase. It helps reduce the impact of changes, makes the code easier to understand, and facilitates the addition of new features. While strict adherence to all the principles may not always be practical in every situation, striving to follow them can significantly improve the quality of your software design.
- Clients should not be forced to depend on interfaces they do not use.
40
+
- This principle suggests that it is better to have small, specific interfaces rather than a large, all-encompassing one. Clients should not be forced to implement interfaces they don't need.
41
+
42
+
5.**D = Dependency Inversion Principle (DIP):**
43
+
44
+
- High-level modules should not depend on low-level modules; both should depend on abstractions. Additionally, abstractions should not depend on details; details should depend on abstractions.
45
+
- This principle encourages the use of abstractions (such as interfaces or abstract classes) to decouple high-level modules from low-level modules, promoting flexibility and maintainability.
46
+
47
+
<br>
48
+
49
+
{: .note }
50
+
By Applying `SOLID` principles in your code leads to a more modular, flexible, and maintainable codebase. Reducing the impact on changes, code becomes easier to understand, facilitates the addition of new features. While strict adherence to all the principles may not always be practical in every situation, striving to follow them can significantly improve the quality of your software design.
51
+
52
+
---
39
53
40
54
## Examples
41
55
42
56
Here are some simple example problems that explore making a coffee. Here is some example "Problem" code:
The initial CoffeeMaker class is responsible for multiple tasks such as grinding coffee beans, brewing coffee, pouring it into a cup, and adding condiments. That's way too many functions for just one class! This violated the SRP because the class had more than one reason to change — any change in the coffee-making process could impact the entire class.
85
100
86
101
How can we solve this? Well, by breaking down and applying Single Responsibilities to each class element, we reduce the need to mess with the whole class.
87
102
103
+
{: .code title="Example:"}
88
104
```cpp
89
105
#include<iostream>
90
106
@@ -145,12 +161,13 @@ public:
145
161
146
162
To adhere to SRP, the CoffeeMaker class is now refactored into separate classes, each responsible for a specific aspect of coffee making (grinding, brewing, pouring, and adding condiments). This separation of concerns makes each class focused on a single responsibility. The CoffeeMaker class then orchestrates these components to make coffee. This way, if there's a change in the coffee grinding process (say we use a different kind of bean), for example, it only affects the CoffeeGrinder class!
The initial design was not closed for modification, especially when introducing new types of coffee. Adding a new coffee type required modifying the existing CoffeeMaker class.
153
169
170
+
{: .code title="Example:"}
154
171
```cpp
155
172
classCoffeeMaker
156
173
{
@@ -175,7 +192,7 @@ public:
175
192
176
193
By using polymorphism and creating abstract classes/interfaces (CoffeeMaker), we open the door for extension. Instead, by using Inheritance and Polymorphism, we can now add a "LatteMaker" and "CappucinoMaker" class without modifying the existing CoffeeMaker class code. This adheres to the OCP, making the system more flexible and extensible.
@@ -185,13 +202,14 @@ By ensuring that derived classes adhere to the same interface as the base class
185
202
186
203
In this example, we solved this just by making `makeCoffee()` virtual and making sure the child classes override this function, but it can get more complex than this!
The initial CoffeeMaker class had methods for grinding coffee beans and adding condiments, which might not be applicable to all types of coffee.
193
210
We can solve this by creating separate interfaces for different aspects of coffee making.
194
211
212
+
{: .code title="Example:"}
195
213
```cpp
196
214
class CoffeeGrinder
197
215
{
@@ -227,12 +245,13 @@ public:
227
245
228
246
By creating separate interfaces (CoffeeGrinder and CondimentAdder), each coffee maker class can implement only the interfaces it needs. This adheres to the ISP, ensuring that no class is forced to implement methods it doesn't use, leading to more modular and focused interfaces.
The initial CoffeeMaker class had direct dependencies on concrete classes (CoffeeGrinder, CoffeeBrewer, CoffeePourer, CondimentAdder), making it hard to change or extend the behavior of these components without modifying the CoffeeMaker class.
235
253
254
+
{: .code title="Example:"}
236
255
```cpp
237
256
// Depend on abstractions (interfaces) rather than concrete implementations.
238
257
classCoffeeMaker
@@ -268,14 +287,13 @@ private:
268
287
269
288
By depending on abstractions (interfaces) instead of concrete implementations, the CoffeeMaker class becomes more flexible. This adheres to DIP, allowing for easy substitution of components. For example, if a new and improved coffee grinder is introduced, it can be swapped without modifying the CoffeeMaker class.
In summary, the approach involved breaking down responsibilities, introducing abstractions/interfaces, and adhering to principles that promote flexibility, extensibility, and maintainability. Each SOLID principle addresses specific concerns, contributing to a more robust and scalable design. This is just a simple example, but there are times where this idea can get highly complex!
0 commit comments