Skip to content

Commit e842265

Browse files
committed
Update SOLID.md
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.
1 parent d5629bb commit e842265

1 file changed

Lines changed: 44 additions & 26 deletions

File tree

docs/Concepts/SOLID.md

Lines changed: 44 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -11,36 +11,51 @@ has_children: false
1111

1212
## What is SOLID?
1313
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.
1515

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.
1926

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):**
2328

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.
2731

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):**
3133

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.
3536

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.
37+
4. **I = Interface Segregation Principle (ISP):**
3738

38-
-----------------------------------------------------------------------
39+
- 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+
---
3953

4054
## Examples
4155

4256
Here are some simple example problems that explore making a coffee. Here is some example "Problem" code:
4357

58+
{: .code title="Example:"}
4459
```cpp
4560
#include <iostream>
4661

@@ -77,14 +92,15 @@ public:
7792
};
7893
```
7994

80-
-----------------------------------------------------------------------
95+
---
8196

8297
### Single Responsibility Principle (SRP):
8398

8499
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.
85100

86101
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.
87102

103+
{: .code title="Example:"}
88104
```cpp
89105
#include <iostream>
90106

@@ -145,12 +161,13 @@ public:
145161

146162
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!
147163

148-
-----------------------------------------------------------------------
164+
---
149165

150166
### Open/Closed Principle (OCP):
151167

152168
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.
153169

170+
{: .code title="Example:"}
154171
```cpp
155172
class CoffeeMaker
156173
{
@@ -175,7 +192,7 @@ public:
175192
176193
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.
177194
178-
-----------------------------------------------------------------------
195+
---
179196
180197
### Liskov Substitution Principle (LSP):
181198
@@ -185,13 +202,14 @@ By ensuring that derived classes adhere to the same interface as the base class
185202
186203
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!
187204
188-
-----------------------------------------------------------------------
205+
---
189206
190207
### Interface Segregation Principle (ISP):
191208
192209
The initial CoffeeMaker class had methods for grinding coffee beans and adding condiments, which might not be applicable to all types of coffee.
193210
We can solve this by creating separate interfaces for different aspects of coffee making.
194211
212+
{: .code title="Example:"}
195213
```cpp
196214
class CoffeeGrinder
197215
{
@@ -227,12 +245,13 @@ public:
227245

228246
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.
229247

230-
-----------------------------------------------------------------------
248+
---
231249

232250
### Dependency Inversion Principle (DIP):
233251

234252
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.
235253

254+
{: .code title="Example:"}
236255
```cpp
237256
// Depend on abstractions (interfaces) rather than concrete implementations.
238257
class CoffeeMaker
@@ -268,14 +287,13 @@ private:
268287
269288
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.
270289
271-
-----------------------------------------------------------------------
290+
---
272291
273292
### Conclusion
274293
275294
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!
276295
277-
-----------------------------------------------------------------------
296+
---
278297
279298
#### Author: JDSherbert
280299
#### Published: 11/12/2023
281-

0 commit comments

Comments
 (0)