├── .vscode
├── c_cpp_properties.json
├── launch.json
└── settings.json
├── README.md
├── behavioral-design-pattern
├── chain-of-responsibility-design-pattern.cpp
├── command-design-pattern.cpp
├── interpreter-design-pattern.cpp
├── iterator-design-pattern.cpp
├── mediator-design-pattern.cpp
├── momento-design-pattern.cpp
├── observer-design-pattern.cpp
├── state-design-pattern.png
├── strategy-design-pattern.cpp
├── template-design-pattern.cpp
└── visitor-design-pattern.cpp
├── creational-design-pattern
├── builder-design-pattern.cpp
├── factory-design-pattern.cpp
└── singleton-design-pattern.cpp
└── structural-design-pattern
├── adapter-design-pattern.cpp
├── bridge-design-pattern.cpp
├── composite-design-pattern.cpp
├── decorator-design-pattern.cpp
├── facade-design-pattern.png
├── flyweight-design-pattern-with-singleton-concept.cpp
├── flyweight-design-pattern.cpp
└── proxy-design-pattern.cpp
/.vscode/c_cpp_properties.json:
--------------------------------------------------------------------------------
1 | {
2 | "configurations": [
3 | {
4 | "name": "windows-gcc-x64",
5 | "includePath": [
6 | "${workspaceFolder}/**"
7 | ],
8 | "compilerPath": "C:/mingw64/bin/gcc.exe",
9 | "cStandard": "${default}",
10 | "cppStandard": "${default}",
11 | "intelliSenseMode": "windows-gcc-x64",
12 | "compilerArgs": [
13 | ""
14 | ]
15 | }
16 | ],
17 | "version": 4
18 | }
--------------------------------------------------------------------------------
/.vscode/launch.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "0.2.0",
3 | "configurations": [
4 | {
5 | "name": "C/C++ Runner: Debug Session",
6 | "type": "cppdbg",
7 | "request": "launch",
8 | "args": [],
9 | "stopAtEntry": false,
10 | "externalConsole": true,
11 | "cwd": "c:/Users/mehta/Desktop/Low-Level-Design-Patterns/behavioral-design-pattern",
12 | "program": "c:/Users/mehta/Desktop/Low-Level-Design-Patterns/behavioral-design-pattern/build/Debug/outDebug",
13 | "MIMode": "gdb",
14 | "miDebuggerPath": "gdb",
15 | "setupCommands": [
16 | {
17 | "description": "Enable pretty-printing for gdb",
18 | "text": "-enable-pretty-printing",
19 | "ignoreFailures": true
20 | }
21 | ]
22 | }
23 | ]
24 | }
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "C_Cpp_Runner.cCompilerPath": "gcc",
3 | "C_Cpp_Runner.cppCompilerPath": "g++",
4 | "C_Cpp_Runner.debuggerPath": "gdb",
5 | "C_Cpp_Runner.cStandard": "",
6 | "C_Cpp_Runner.cppStandard": "",
7 | "C_Cpp_Runner.msvcBatchPath": "C:/Program Files/Microsoft Visual Studio/VR_NR/Community/VC/Auxiliary/Build/vcvarsall.bat",
8 | "C_Cpp_Runner.useMsvc": false,
9 | "C_Cpp_Runner.warnings": [
10 | "-Wall",
11 | "-Wextra",
12 | "-Wpedantic",
13 | "-Wshadow",
14 | "-Wformat=2",
15 | "-Wcast-align",
16 | "-Wconversion",
17 | "-Wsign-conversion",
18 | "-Wnull-dereference"
19 | ],
20 | "C_Cpp_Runner.msvcWarnings": [
21 | "/W4",
22 | "/permissive-",
23 | "/w14242",
24 | "/w14287",
25 | "/w14296",
26 | "/w14311",
27 | "/w14826",
28 | "/w44062",
29 | "/w44242",
30 | "/w14905",
31 | "/w14906",
32 | "/w14263",
33 | "/w44265",
34 | "/w14928"
35 | ],
36 | "C_Cpp_Runner.enableWarnings": true,
37 | "C_Cpp_Runner.warningsAsError": false,
38 | "C_Cpp_Runner.compilerArgs": [],
39 | "C_Cpp_Runner.linkerArgs": [],
40 | "C_Cpp_Runner.includePaths": [],
41 | "C_Cpp_Runner.includeSearch": [
42 | "*",
43 | "**/*"
44 | ],
45 | "C_Cpp_Runner.excludeSearch": [
46 | "**/build",
47 | "**/build/**",
48 | "**/.*",
49 | "**/.*/**",
50 | "**/.vscode",
51 | "**/.vscode/**"
52 | ],
53 | "C_Cpp_Runner.useAddressSanitizer": false,
54 | "C_Cpp_Runner.useUndefinedSanitizer": false,
55 | "C_Cpp_Runner.useLeakSanitizer": false,
56 | "C_Cpp_Runner.showCompilationTime": false,
57 | "C_Cpp_Runner.useLinkTimeOptimization": false,
58 | "C_Cpp_Runner.msvcSecureNoWarnings": false
59 | }
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | LOW-LEVEL-DESIGN-PATTERNS
5 |
6 | Crafting brilliance through low-level design mastery.
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 | ## Table of Contents
22 |
23 | - [ Overview](#-overview)
24 | - [ Features](#-features)
25 | - [ Project Structure](#-project-structure)
26 | - [ Project Index](#-project-index)
27 | - [ Getting Started](#-getting-started)
28 | - [ Prerequisites](#-prerequisites)
29 | - [ Installation](#-installation)
30 | - [ Contributing](#-contributing)
31 | - [ License](#-license)
32 | - [ Acknowledgments](#-acknowledgments)
33 |
34 | ---
35 |
36 | ## Overview
37 |
38 | The Low-Level-Design-Patterns project offers a collection of practical code examples showcasing various design patterns like Builder, Singleton, and Factory. It simplifies creating complex objects, managing database connections efficiently, and enabling dynamic behaviors in software systems. Ideal for developers seeking hands-on guidance in designing robust and scalable applications.
39 |
40 | ---
41 |
42 | ## Features
43 |
44 | | | Folder | Summary |
45 | | :-- | :---------------------: | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
46 | | ⚙️ | **Creational Patterns** | - **Builder**: Separates the construction of a complex object from its representation.
- **Singleton**: Ensures a class has only one instance and provides a global point of access to it.
- **Factory**: Defines an interface for creating an object, but lets subclasses alter the type of objects that will be created.
|
47 | | 🔩 | **Structural Patterns** | - **Adapter**: Allows incompatible interfaces to work together.
- **Bridge**: Decouples an abstraction from its implementation so that the two can vary independently.
- **Composite**: Composes objects into tree structures to represent part-whole hierarchies.
- **Decorator**: Adds additional responsibilities to an object dynamically.
- **Facade**: Provides a simplified interface to a complex subsystem.
- **Flyweight**: Reduces the cost of creating and manipulating a large number of similar objects.
- **Proxy**: Provides a surrogate or placeholder for another object to control access to it.
|
48 | | 📄 | **Behavioral Patterns** | - **Chain of Responsibility**: Passes a request along a chain of handlers.
- **Command**: Encapsulates a request as an object, thereby allowing for parameterization and queuing of requests.
- **Interpreter**: Defines a grammatical representation for a language and an interpreter to interpret the grammar.
- **Iterator**: Provides a way to access the elements of an aggregate object sequentially without exposing its underlying representation.
- **Mediator**: Defines an object that encapsulates how a set of objects interact.
- **Memento**: Captures and externalizes an object's internal state without violating encapsulation.
- **Observer**: Defines a one-to-many dependency between objects so that when one object changes state, all its dependents are notified and updated automatically.
- **State**: Allows an object to alter its behavior when its internal state changes.
- **Strategy**: Defines a family of algorithms, encapsulates each one, and makes them interchangeable.
- **Template Method**: Defines the skeleton of an algorithm in a method, deferring some steps to subclasses.
- **Visitor**: Represents an operation to be performed on the elements of an object structure.
|
49 |
50 | ---
51 |
52 | ## Project Structure
53 |
54 | ```sh
55 | └── Low-Level-Design-Patterns/
56 | ├── README.md
57 | ├── behavioral-design-pattern
58 | │ ├── chain-of-responsibility-design-pattern.cpp
59 | │ ├── command-design-pattern.cpp
60 | │ ├── interpreter-design-pattern.cpp
61 | │ ├── iterator-design-pattern.cpp
62 | │ ├── mediator-design-pattern.cpp
63 | │ ├── momento-design-pattern.cpp
64 | │ ├── observer-design-pattern.cpp
65 | │ ├── state-design-pattern.png
66 | │ ├── strategy-design-pattern.cpp
67 | │ ├── template-design-pattern.cpp
68 | │ └── visitor-design-pattern.cpp
69 | ├── creational-design-pattern
70 | │ ├── builder-design-pattern.cpp
71 | │ ├── factory-design-pattern.cpp
72 | │ └── singleton-design-pattern.cpp
73 | └── structural-design-pattern
74 | ├── adapter-design-pattern.cpp
75 | ├── bridge-design-pattern.cpp
76 | ├── composite-design-pattern.cpp
77 | ├── decorator-design-pattern.cpp
78 | ├── facade-design-pattern.png
79 | ├── flyweight-design-pattern-with-singleton-concept.cpp
80 | ├── flyweight-design-pattern.cpp
81 | └── proxy-design-pattern.cpp
82 | ```
83 |
84 | ### Project Index
85 |
86 |
87 | LOW-LEVEL-DESIGN-PATTERNS/
88 |
95 |
96 | creational-design-pattern
97 |
98 |
99 |
100 | builder-design-pattern.cpp |
101 | - Demonstrates the Builder design pattern for creating complex objects step by step - Encapsulates object construction, enabling easy management and extension - Concrete builders like EngineeringStudentBuilder and MBAStudentBuilder set specific attributes for different types of students - Main function showcases building and printing details of Engineering and MBA students. |
102 |
103 |
104 | singleton-design-pattern.cpp |
105 | - Implements singleton design patterns for database connections with eager, lazy, and double-checked locking initialization methods - Provides global access to single instances of classes, ensuring thread safety and efficient resource usage - Demonstrates different strategies for creating and accessing singleton objects in the codebase architecture. |
106 |
107 |
108 | factory-design-pattern.cpp |
109 | - Implements Factory Pattern to create various shapes like Circle, Square, and Rectangle - Defines Shape superclass with draw method and concrete classes for each shape - ShapeFactory class generates shape objects based on input strings - Demonstrates pattern usage by creating a Rectangle object and calling its draw method. |
110 |
111 |
112 |
113 |
114 |
115 | behavioral-design-pattern
116 |
117 |
118 |
119 | strategy-design-pattern.cpp |
120 | - Demonstrates the Strategy Design Pattern for dynamic driving behaviors in vehicles - Encapsulates various driving strategies (e.g., Sport, Normal, Passenger) as separate classes - The Vehicle class can change strategies dynamically, promoting flexibility and scalability without modifying the Vehicle class itself. |
121 |
122 |
123 | template-design-pattern.cpp |
124 | - Implements a Template Method Design Pattern for payment processing - Defines a base class with common steps and abstract methods for subclasses to implement specific payment types - Demonstrates sending money to a friend and a merchant by overriding the template methods - Executed through instances of PayToFriend and PayToMerch classes. |
125 |
126 |
127 | observer-design-pattern.cpp |
128 | - Implements observer design pattern for stock updates - Defines observables for iPhone and Samsung stocks, with mobile and email alert observers - Demonstrates notifications to observers based on stock count changes. |
129 |
130 |
131 | chain-of-responsibility-design-pattern.cpp |
132 | - Implements a Chain of Responsibility design pattern for logging messages based on their severity levels - The code defines different log processors for handling INFO, DEBUG, and ERROR messages in a chain - By passing messages through the chain, it ensures that each message is processed by the appropriate log processor without the sender needing to know the specific handler. |
133 |
134 |
135 | mediator-design-pattern.cpp |
136 | - Demonstrates the Mediator Design Pattern, fostering loose coupling between objects by centralizing communication through a mediator - Objects interact indirectly via the mediator, enhancing system maintainability and flexibility - The code showcases how bidders in an auction place bids and receive notifications through the mediator, streamlining communication and reducing dependencies. |
137 |
138 |
139 | interpreter-design-pattern.cpp |
140 | - Demonstrates the Interpreter Design Pattern by evaluating complex mathematical expressions using terminal and non-terminal expressions within a defined context - The code creates a context to store variable values, constructs expressions for multiplication and addition, and outputs the result of the expression evaluation. |
141 |
142 |
143 | command-design-pattern.cpp |
144 | - Implements the Command Design Pattern to decouple command execution from command producers - Defines commands for an Air Conditioner, allowing operations like turning on/off and setting temperature - Utilizes an invoker class to manage and execute commands, showcasing features like undo/redo functionality. |
145 |
146 |
147 | visitor-design-pattern.cpp |
148 | - Implements Visitor Design Pattern to separate operations (pricing, maintenance) from room classes - Defines visitors for different room types to perform specific operations without modifying room classes - Main function demonstrates pricing and maintenance operations on single, double, and deluxe rooms using respective visitor instances. |
149 |
150 |
151 | iterator-design-pattern.cpp |
152 | - Implements the Iterator Design Pattern to enable sequential access to a collection of books without exposing its structure - The code defines classes for books, iterators, and libraries, showcasing how to iterate over and print book names in a library using an iterator. |
153 |
154 |
155 | momento-design-pattern.cpp |
156 | - Demonstrates the Memento Design Pattern by enabling objects to be restored to previous states without revealing implementation details - The code showcases saving and restoring object states using Mementos managed by a CareTaker, facilitating undo/redo functionality within the project's architecture. |
157 |
158 |
159 |
160 |
161 |
162 | structural-design-pattern
163 |
164 |
165 |
166 | flyweight-design-pattern.cpp |
167 | - Demonstrates the Flyweight Design Pattern to optimize memory usage by sharing common data among similar objects - The code defines interfaces for letters, concrete letter implementations, and a factory to manage object creation and reuse - By creating and displaying letters using the factory, it showcases efficient memory utilization through object sharing. |
168 |
169 |
170 | bridge-design-pattern.cpp |
171 | - Demonstrates the Bridge Design Pattern by decoupling abstractions from implementations, allowing independent variation - Defines breathing processes for land and water entities, showcasing how Dogs and Fish can use different implementors - This promotes extensibility and flexibility in managing diverse living things. |
172 |
173 |
174 | flyweight-design-pattern-with-singleton-concept.cpp |
175 | - Demonstrates the Flyweight Design Pattern by efficiently managing memory usage through object sharing - The code showcases the creation and reuse of letter objects using a Singleton Factory, emphasizing memory optimization for large quantities of similar objects. |
176 |
177 |
178 | decorator-design-pattern.cpp |
179 | - Implements the Decorator Design Pattern for pizzas, allowing dynamic addition of toppings to base pizza objects - Demonstrates how to enhance pizza objects with Mushroom and Cheese toppings while maintaining scalability and reusability in the codebase architecture. |
180 |
181 |
182 | adapter-design-pattern.cpp |
183 | - Implements the Adapter Design Pattern to bridge incompatible interfaces, converting weight from pounds to kilograms - The code creates classes for weighing machines in pounds and kilograms, demonstrating adaptation between the two units. |
184 |
185 |
186 | proxy-design-pattern.cpp |
187 | - Implements a Proxy Design Pattern to control access to an Employee Database - The code defines classes for Employee, EmployeeDB, EmployeeDBImpl, and EmployeeDBProxy - The proxy restricts access based on client permissions, allowing creation and retrieval of employee records - The main function demonstrates creating an employee record and retrieving it based on client roles. |
188 |
189 |
190 | composite-design-pattern.cpp |
191 | - Demonstrates the Composite Design Pattern by creating a hierarchical structure of directories and files - Allows uniform treatment of individual objects and compositions - Enables representing part-whole hierarchies where files and directories are handled uniformly - The code showcases how directories can contain files and subdirectories in a tree-like manner. |
192 |
193 |
194 |
195 |
196 |
197 |
198 | ---
199 |
200 | ## Getting Started
201 |
202 | ### Prerequisites
203 |
204 | Before getting started with Low-Level-Design-Patterns, ensure your runtime environment meets the following requirements:
205 |
206 | - **Programming Language:** CPP
207 |
208 | ### Installation
209 |
210 | Install Low-Level-Design-Patterns using one of the following methods:
211 |
212 | **Build from source:**
213 |
214 | 1. Clone the Low-Level-Design-Patterns repository:
215 |
216 | ```sh
217 | ❯ git clone https://github.com/samyakmehta28/Low-Level-Design-Patterns
218 | ```
219 |
220 | 2. Navigate to the project directory:
221 |
222 | ```sh
223 | ❯ cd Low-Level-Design-Patterns
224 | ```
225 |
226 | ---
227 |
228 | ## Contributing
229 |
230 | - **💬 [Join the Discussions](https://github.com/samyakmehta28/Low-Level-Design-Patterns/discussions)**: Share your insights, provide feedback, or ask questions.
231 | - **🐛 [Report Issues](https://github.com/samyakmehta28/Low-Level-Design-Patterns/issues)**: Submit bugs found or log feature requests for the `Low-Level-Design-Patterns` project.
232 | - **💡 [Submit Pull Requests](https://github.com/samyakmehta28/Low-Level-Design-Patterns/blob/main/CONTRIBUTING.md)**: Review open PRs, and submit your own PRs.
233 |
234 |
235 | Contributing Guidelines
236 |
237 | 1. **Fork the Repository**: Start by forking the project repository to your github account.
238 | 2. **Clone Locally**: Clone the forked repository to your local machine using a git client.
239 | ```sh
240 | git clone https://github.com/samyakmehta28/Low-Level-Design-Patterns
241 | ```
242 | 3. **Create a New Branch**: Always work on a new branch, giving it a descriptive name.
243 | ```sh
244 | git checkout -b new-feature-x
245 | ```
246 | 4. **Make Your Changes**: Develop and test your changes locally.
247 | 5. **Commit Your Changes**: Commit with a clear message describing your updates.
248 | ```sh
249 | git commit -m 'Implemented new feature x.'
250 | ```
251 | 6. **Push to github**: Push the changes to your forked repository.
252 | ```sh
253 | git push origin new-feature-x
254 | ```
255 | 7. **Submit a Pull Request**: Create a PR against the original project repository. Clearly describe the changes and their motivations.
256 | 8. **Review**: Once your PR is reviewed and approved, it will be merged into the main branch. Congratulations on your contribution!
257 |
258 |
259 |
260 | Contributor Graph
261 |
262 |
263 |
264 |
265 |
266 |
267 |
268 |
269 | ---
270 |
271 | ## License
272 |
273 | This project is protected under the [SELECT-A-LICENSE](https://choosealicense.com/licenses) License. For more details, refer to the [LICENSE](https://choosealicense.com/licenses/) file.
274 |
275 | ---
276 |
277 | ## Acknowledgments
278 |
279 | - I would like to express my sincere gratitude to Shreyansh Jain for his invaluable contributions through his YouTube playlist on Low-Level System Design. This collection of C++ implementations of various design patterns was primarily inspired by the examples presented in his videos. While I have closely followed the examples provided in his content, I have adapted and implemented them in C++.
280 |
281 | - You can find Shreyansh Jain's YouTube playlist here: [Low-Level System Design Playlist](https://www.youtube.com/playlist?list=PL6W8uoQQ2c61X_9e6Net0WdYZidm7zooW).
282 |
283 | ---
284 |
--------------------------------------------------------------------------------
/behavioral-design-pattern/chain-of-responsibility-design-pattern.cpp:
--------------------------------------------------------------------------------
1 |
2 | // The Chain of Responsibility is a behavioral design pattern that allows an object to pass a request along a chain of potential handlers until one of them handles it. This pattern decouples the sender of a request from its receiver, allowing multiple objects to handle the request without the sender needing to know which object will handle it.
3 | #include
4 | using namespace std;
5 |
6 | /**
7 | * The LogProcessor class is the base class for all log processors in the chain.
8 | * It provides a common interface for handling log messages and passing them to
9 | * the next processor in the chain.
10 | */
11 | class LogProcessor{
12 | protected:
13 | LogProcessor *nextLogProcessor;
14 |
15 | public:
16 | const int INFO = 1;
17 | const int DEBUG = 2;
18 | const int ERROR = 3;
19 |
20 | /**
21 | * Constructor for LogProcessor.
22 | *
23 | * @param nlp A pointer to the next LogProcessor in the chain. This allows
24 | * the current processor to pass the request to the next processor
25 | * if it cannot handle it. If this is the last processor in the chain,
26 | * nlp should be NULL.
27 | */
28 |
29 | LogProcessor(LogProcessor *nlp){
30 | nextLogProcessor = nlp;
31 | }
32 | /**
33 | * Pass a log message to the next processor in the chain, if any.
34 | *
35 | * If the current processor cannot handle the log message (i.e., if the log
36 | * level is greater than the level handled by the processor), the request is
37 | * passed to the next processor in the chain. If the current processor is the
38 | * last one in the chain, the message is dropped.
39 | *
40 | * @param logLevel The level of the log message. This is used to determine
41 | * whether the current processor can handle the message.
42 | * @param message The log message itself.
43 | */
44 | virtual void log(const int logLevel, string message){
45 | if(nextLogProcessor!=NULL){
46 | cout<<"going next"<log(logLevel, message);
48 | }
49 | }
50 | };
51 |
52 | class InfoLogProcessor: public LogProcessor{
53 | public:
54 | InfoLogProcessor(LogProcessor *nlp): LogProcessor(nlp){}
55 | /**
56 | * Handle a log message if its level is INFO.
57 | *
58 | * If the level of the message is INFO, the message is printed to the console.
59 | * Otherwise, the message is passed to the next processor in the chain.
60 | *
61 | * @param logLevel The level of the message. If this is INFO, the message is
62 | * handled; otherwise, it is passed to the next processor.
63 | * @param message The message itself.
64 | */
65 | void log(const int logLevel, string message){
66 | if(logLevel == INFO){
67 | cout<<"INFO "<log(logProcessor->ERROR, "get error");
149 | }
--------------------------------------------------------------------------------
/behavioral-design-pattern/command-design-pattern.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | using namespace std;
3 | //Command Design Pattern: The Command Design Pattern is a behavioral design pattern that turns a request into a stand-alone object that contains all the information about the request. This transformation allows the decoupling of objects that produce commands from objects that execute them. This pattern is often used to implement features such as undo/redo, logging, and queuing of requests.
4 |
5 |
6 | //Receiver class
7 | //This class represents the receiver of the command. In this case, it is an
8 | //Air Conditioner that has methods to turn it on and off and set the temperature.
9 | class AirConditioner{
10 | private:
11 | bool isOn;
12 | int temperature;
13 |
14 | public:
15 | AirConditioner(): isOn(false), temperature(24){}
16 | /**
17 | * @brief Turns the air conditioner on.
18 | *
19 | * This method sets the isOn flag to true and prints a message indicating
20 | * that the air conditioner has been turned on.
21 | */
22 | void turnACOn(){
23 | isOn=true;
24 | cout<<"AC is turned On"<turnACOn();
100 | }
101 |
102 | /**
103 | * @brief Undoes the command.
104 | *
105 | * This method turns off the air conditioner, reversing the
106 | * effect of the execute() method.
107 | */
108 | void undo(){
109 | airConditioner->turnACOff();
110 | }
111 | };
112 |
113 | class TurnACOffCommand: public ICommand {
114 | private:
115 | AirConditioner *airConditioner;
116 |
117 | public:
118 |
119 | /**
120 | * @brief Executes the command.
121 | *
122 | * This method turns off the air conditioner.
123 | */
124 | TurnACOffCommand(AirConditioner *ac): airConditioner(ac){};
125 | /**
126 | * @brief Executes the command.
127 | *
128 | * This method turns off the air conditioner.
129 | */
130 | void execute(){
131 | airConditioner->turnACOff();
132 | }
133 |
134 | /**
135 | * @brief Reverts the command.
136 | *
137 | * This method turns the air conditioner back on, undoing the previous command
138 | * that turned it off.
139 | */
140 |
141 | void undo(){
142 | airConditioner->turnACOn();
143 | }
144 | };
145 |
146 | /**
147 | * @brief A command to set the temperature of the air conditioner.
148 | *
149 | * This class encapsulates the logic of setting the temperature of the air
150 | * conditioner. It takes in an AirConditioner object and an integer temperature
151 | * in the constructor. In the execute() method, it sets the temperature of the
152 | * air conditioner to the given next_temperature. In the undo() method, it sets
153 | * the temperature of the air conditioner back to the previous_temperature.
154 | */
155 | class SetTemperatureCommand: public ICommand {
156 | private:
157 | AirConditioner *airConditioner;
158 | int previous_temperature;
159 | int next_temperature;
160 |
161 | public:
162 | /**
163 | * @brief Constructor for SetTemperatureCommand.
164 | *
165 | * This constructor takes in an AirConditioner object and an integer
166 | * temperature. It sets the airConditioner field to the given AirConditioner
167 | * object and next_temperature field to the given temperature. It also
168 | * records the previous temperature by calling getTemperature() on the
169 | * AirConditioner object.
170 | * @param ac The AirConditioner object to be controlled.
171 | * @param temperature The temperature to be set.
172 | */
173 | SetTemperatureCommand(AirConditioner *ac, int temperature): airConditioner(ac), next_temperature(temperature){
174 | previous_temperature = airConditioner->getTemperature();
175 | }
176 | void execute(){
177 | airConditioner->setTemperature(next_temperature);
178 | /**
179 | * Sets the temperature of the air conditioner to the next_temperature.
180 | * This method is an implementation of the execute method of the
181 | * ICommand interface.
182 | */
183 | }
184 | /**
185 | * Reverts the air conditioner's temperature to the previously
186 | * recorded temperature. This method is an implementation of
187 | * the undo method of the ICommand interface, allowing the
188 | * command to reverse its effect.
189 | */
190 | void undo(){
191 | airConditioner->setTemperature(previous_temperature);
192 | }
193 | };
194 |
195 | //Invoker
196 |
197 | /**
198 | * Remote class is an invoker in the command design pattern.
199 | * It uses a stack to store commands and uses the command
200 | * interface to execute and undo commands.
201 | * The invoker is responsible for managing the command
202 | * stack and executing the commands in the stack.
203 | */
204 | class Remote{
205 | private:
206 | stackcommands;
207 |
208 | public:
209 | /**
210 | * Remote constructor.
211 | * Removes all commands from the stack.
212 | */
213 | Remote(){
214 | while(!commands.empty()){
215 | commands.pop();
216 | }
217 | }
218 | /**
219 | * Adds a command to the top of the stack.
220 | * @param cmd The command to be added to the stack.
221 | */
222 | void setCommand(ICommand *cmd){
223 | commands.push(cmd);
224 | }
225 |
226 | /**
227 | * Calls the execute() method of the command at the top of the stack.
228 | * Does nothing if the stack is empty.
229 | */
230 | void pressButton(){
231 | if(!commands.empty()){
232 | ICommand *curr_command = commands.top();
233 | curr_command->execute();
234 | }
235 | }
236 |
237 | /**
238 | * Pops the last command from the stack and calls its undo() method.
239 | * This can be used to revert the state of the AirConditioner to its state
240 | * before the last command was executed.
241 | */
242 | void undoButton(){
243 | if(!commands.empty()){
244 | ICommand *curr_command = commands.top();
245 | curr_command->undo();
246 | commands.pop();
247 | }
248 | }
249 | };
250 |
251 |
252 | /**
253 | * @brief Main function to demonstrate the command design pattern.
254 | *
255 | * This function creates an AirConditioner object and a Remote object.
256 | * It then sets the command on the remote to a TurnACOnCommand and presses the button.
257 | * After that, it sets the command on the remote to a SetTemperatureCommand for 30 degrees and presses the button.
258 | * Finally, it undoes the previous two commands by pressing the undo button twice.
259 | */
260 | int main(){
261 | AirConditioner *airConditioner = new AirConditioner();
262 | Remote *remote = new Remote();
263 |
264 | remote->setCommand(new TurnACOnCommand(airConditioner));
265 | remote->pressButton();
266 | remote->setCommand(new SetTemperatureCommand(airConditioner, 30));
267 | remote->pressButton();
268 | remote->undoButton();
269 | remote->undoButton();
270 | }
271 |
--------------------------------------------------------------------------------
/behavioral-design-pattern/interpreter-design-pattern.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | using namespace std;
3 |
4 | // Interpreter Design Pattern:
5 | // The Interpreter Design Pattern is a behavioral design pattern used to define a grammar
6 | // for a simple language and an interpreter that uses the grammar to interpret statements
7 | // in the language. It provides a way to evaluate sentences or expressions in a defined
8 | // language or format.
9 |
10 | // Context class
11 | // The Context class is used to store and retrieve variable values in the form of key-value pairs.
12 | // It serves as the environment for the interpretation process, where variables and their values
13 | // are maintained.
14 | class Context {
15 | private:
16 | map m; // Stores variable-value pairs
17 |
18 | public:
19 | /**
20 | * @brief Constructs a new Context object.
21 | *
22 | * This constructor initializes the internal map by clearing any pre-existing values.
23 | */
24 | Context() {
25 | m.clear();
26 | }
27 |
28 | /**
29 | * @brief Adds a variable and its value to the context.
30 | *
31 | * @param var The variable name as a string.
32 | * @param val The value of the variable as an integer.
33 | */
34 | void put(string var, int val) {
35 | m[var] = val;
36 | }
37 |
38 | /**
39 | * @brief Retrieves the value of a variable from the context.
40 | *
41 | * @param var The variable name as a string.
42 | * @return The value of the variable as an integer.
43 | */
44 | int get(string var) {
45 | return m[var];
46 | }
47 | };
48 |
49 | // AbstractExpression class
50 | // The AbstractExpression class is an interface for all expression types.
51 | // It defines the interpreter method, which must be implemented by all concrete expressions.
52 | class AbstractExpression {
53 | public:
54 | /**
55 | * @brief Evaluates the expression using the provided context.
56 | *
57 | * @param context A pointer to the Context object containing variable values.
58 | * @return The result of the interpretation as an integer.
59 | */
60 | virtual int interpreter(Context *context) = 0;
61 | };
62 |
63 | // TerminalExpression class
64 | // The TerminalExpression class represents variables in the expression.
65 | // It evaluates a variable by retrieving its value from the context.
66 | class TerminalExpression : public AbstractExpression {
67 | string variable; // The variable name
68 |
69 | public:
70 | /**
71 | * @brief Constructs a TerminalExpression with a variable name.
72 | *
73 | * @param var The variable name as a string.
74 | */
75 | TerminalExpression(string var) : variable(var) {}
76 |
77 | /**
78 | * @brief Evaluates the variable by retrieving its value from the context.
79 | *
80 | * @param context A pointer to the Context object containing variable values.
81 | * @return The value of the variable as an integer.
82 | */
83 | int interpreter(Context *context) {
84 | return context->get(variable);
85 | }
86 | };
87 |
88 | // MultiplyNonTerminalExpression class
89 | // This class represents a multiplication operation between two expressions.
90 | class MultiplyNonTerminalExpression : public AbstractExpression {
91 | AbstractExpression *leftExpresion; // The left-hand operand
92 | AbstractExpression *rightExpression; // The right-hand operand
93 |
94 | public:
95 | /**
96 | * @brief Constructs a MultiplyNonTerminalExpression with two operands.
97 | *
98 | * @param l A pointer to the left-hand expression.
99 | * @param r A pointer to the right-hand expression.
100 | */
101 | MultiplyNonTerminalExpression(AbstractExpression *l, AbstractExpression *r)
102 | : leftExpresion(l), rightExpression(r) {}
103 |
104 | /**
105 | * @brief Evaluates the multiplication operation.
106 | *
107 | * @param context A pointer to the Context object containing variable values.
108 | * @return The result of the multiplication as an integer.
109 | */
110 | int interpreter(Context *context) {
111 | return (leftExpresion->interpreter(context) * rightExpression->interpreter(context));
112 | }
113 | };
114 |
115 | // SumNonTerminalExpression class
116 | // This class represents an addition operation between two expressions.
117 | class SumNonTerminalExpression : public AbstractExpression {
118 | AbstractExpression *leftExpresion; // The left-hand operand
119 | AbstractExpression *rightExpression; // The right-hand operand
120 |
121 | public:
122 | /**
123 | * @brief Constructs a SumNonTerminalExpression with two operands.
124 | *
125 | * @param l A pointer to the left-hand expression.
126 | * @param r A pointer to the right-hand expression.
127 | */
128 | SumNonTerminalExpression(AbstractExpression *l, AbstractExpression *r)
129 | : leftExpresion(l), rightExpression(r) {}
130 |
131 | /**
132 | * @brief Evaluates the addition operation.
133 | *
134 | * @param context A pointer to the Context object containing variable values.
135 | * @return The result of the addition as an integer.
136 | */
137 | int interpreter(Context *context) {
138 | return (leftExpresion->interpreter(context) + rightExpression->interpreter(context));
139 | }
140 | };
141 |
142 | // Main function
143 | /**
144 | * @brief Demonstrates the Interpreter Design Pattern.
145 | *
146 | * This function creates a context to store variable values and uses terminal
147 | * and non-terminal expressions to evaluate a complex mathematical expression.
148 | * The result of the expression is printed to the console.
149 | */
150 | int main() {
151 | // Create a context and populate it with variable values
152 | Context *context = new Context();
153 | context->put("num1", 2);
154 | context->put("num2", 3);
155 | context->put("num3", 4);
156 | context->put("num4", 5);
157 |
158 | // Construct expressions
159 | AbstractExpression *expression1 = new MultiplyNonTerminalExpression(
160 | new TerminalExpression("num1"), new TerminalExpression("num2"));
161 | AbstractExpression *expression2 = new MultiplyNonTerminalExpression(
162 | new TerminalExpression("num3"), new TerminalExpression("num4"));
163 | AbstractExpression *expression3 = new SumNonTerminalExpression(expression1, expression2);
164 |
165 | // Evaluate the expression and print the result
166 | cout << "Value of expression is " << expression3->interpreter(context) << endl;
167 |
168 | return 0;
169 | }
170 |
--------------------------------------------------------------------------------
/behavioral-design-pattern/iterator-design-pattern.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | using namespace std;
3 |
4 | // Iterator Design Pattern:
5 | // The Iterator Design Pattern is a behavioral design pattern that provides a way to access
6 | // elements of a collection (such as a list, set, or array) sequentially without exposing
7 | // the underlying representation. It standardizes iteration over elements regardless of the collection's structure.
8 |
9 | // Book class
10 | // Represents a book with a name and cost.
11 | class Book {
12 | private:
13 | string bookName; // Name of the book
14 | int bookCost; // Cost of the book
15 |
16 | public:
17 | /**
18 | * @brief Constructs a new Book object.
19 | *
20 | * @param bn The name of the book.
21 | * @param bc The cost of the book.
22 | */
23 | Book(string bn, int bc) : bookName(bn), bookCost(bc) {}
24 |
25 | /**
26 | * @brief Gets the name of the book.
27 | *
28 | * @return The book name as a string.
29 | */
30 | string getBookName() {
31 | return bookName;
32 | }
33 |
34 | /**
35 | * @brief Gets the cost of the book.
36 | *
37 | * @return The book cost as an integer.
38 | */
39 | int getBookCost() {
40 | return bookCost;
41 | }
42 | };
43 |
44 | // Iterator class (Abstract Template)
45 | // Defines an interface for iterating over a collection.
46 | template
47 | class Iterator {
48 | public:
49 | /**
50 | * @brief Checks if there are more elements to iterate over.
51 | *
52 | * @return True if more elements exist, otherwise false.
53 | */
54 | virtual bool hasNext() = 0;
55 |
56 | /**
57 | * @brief Retrieves the next element in the collection.
58 | *
59 | * @return The next element of type T.
60 | */
61 | virtual T next() = 0;
62 | };
63 |
64 | // BookIterator class
65 | // Implements the Iterator interface for the Book class.
66 | class BookIterator : public Iterator {
67 | private:
68 | vector books; // Collection of books
69 | int index; // Current position in the collection
70 |
71 | public:
72 | /**
73 | * @brief Constructs a BookIterator object.
74 | *
75 | * @param b A vector of books to iterate over.
76 | */
77 | BookIterator(vector b) {
78 | books = b;
79 | index = 0; // Start at the beginning of the collection
80 | }
81 |
82 | /**
83 | * @brief Checks if there are more books to iterate over.
84 | *
85 | * @return True if more books exist, otherwise false.
86 | */
87 | bool hasNext() {
88 | return index < books.size();
89 | }
90 |
91 | /**
92 | * @brief Retrieves the next book in the collection.
93 | *
94 | * @return The next Book object.
95 | */
96 | Book next() {
97 | Book book = books[index];
98 | index++;
99 | return book;
100 | }
101 | };
102 |
103 | // Aggregator class (Abstract Template)
104 | // Defines an interface for creating an iterator for a collection.
105 | template
106 | class Aggregator {
107 | public:
108 | /**
109 | * @brief Creates and returns an iterator for the collection.
110 | *
111 | * @return A pointer to an Iterator of type T.
112 | */
113 | virtual Iterator* createIterator() = 0;
114 | };
115 |
116 | // Library class
117 | // Implements the Aggregator interface to manage a collection of books.
118 | class Library : public Aggregator {
119 | private:
120 | vector books; // Collection of books
121 |
122 | public:
123 | /**
124 | * @brief Constructs a new Library object.
125 | *
126 | * This constructor initializes the books collection as empty.
127 | */
128 | Library() {
129 | books.clear();
130 | }
131 |
132 | /**
133 | * @brief Creates and returns an iterator for the books collection.
134 | *
135 | * @return A pointer to a BookIterator object.
136 | */
137 | Iterator* createIterator() {
138 | return new BookIterator(books);
139 | }
140 |
141 | /**
142 | * @brief Adds a book to the library.
143 | *
144 | * @param book The Book object to add.
145 | */
146 | void addBook(Book book) {
147 | books.push_back(book);
148 | }
149 | };
150 |
151 | // Main function
152 | /**
153 | * @brief Demonstrates the Iterator Design Pattern.
154 | *
155 | * This function creates a Library object, adds books to it, and uses an iterator to
156 | * sequentially access and print the names of the books in the library.
157 | */
158 | int main() {
159 | // Create a library object
160 | Library *library = new Library();
161 |
162 | // Add books to the library
163 | library->addBook(Book("book1", 35));
164 | library->addBook(Book("book2", 45));
165 | library->addBook(Book("book3", 55));
166 | library->addBook(Book("book4", 65));
167 |
168 | // Create an iterator for the library
169 | Iterator* iterator = library->createIterator();
170 |
171 | // Use the iterator to traverse and print the book names
172 | while (iterator->hasNext()) {
173 | cout << iterator->next().getBookName() << endl;
174 | }
175 |
176 | // Clean up dynamically allocated memory
177 | delete iterator;
178 | delete library;
179 |
180 | return 0;
181 | }
182 |
--------------------------------------------------------------------------------
/behavioral-design-pattern/mediator-design-pattern.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | using namespace std;
3 |
4 | // Mediator Design Pattern:
5 | // The Mediator Design Pattern is a behavioral design pattern that promotes loose coupling between objects by centralizing communication through a mediator object.
6 | // Instead of objects communicating directly with each other, they send messages to a mediator, which handles the communication and interaction logic.
7 | // This reduces dependencies between interacting objects, making the system more maintainable and flexible.
8 |
9 | // Abstract interface for a bidder in the auction
10 | class IBidder {
11 | public:
12 | virtual void placeBid(int bidAmount) = 0; // Places a bid
13 | virtual void receiveBidNotification(string bidderName, int bidAmount) = 0; // Receives notification of other bids
14 | virtual string getName() = 0; // Returns the name of the bidder
15 | };
16 |
17 | // Abstract interface for the mediator
18 | class IAuctionMediator {
19 | public:
20 | virtual void addBidder(IBidder *bidder) = 0; // Adds a bidder to the auction
21 | virtual void placeBid(IBidder *bidder, int bidAmount) = 0; // Handles the bid placement
22 | };
23 |
24 | // Concrete implementation of a bidder
25 | class Bidder : public IBidder {
26 | string name; // Name of the bidder
27 | IAuctionMediator *auctionMediator; // Reference to the mediator
28 |
29 | public:
30 | // Constructor to initialize the bidder and register with the mediator
31 | Bidder(string nm, IAuctionMediator *am) : name(nm), auctionMediator(am) {
32 | auctionMediator->addBidder(this); // Register bidder with the mediator
33 | }
34 |
35 | // Places a bid and notifies the mediator
36 | void placeBid(int bidAmount) override {
37 | cout << name << " placed a bid of " << bidAmount << endl;
38 | auctionMediator->placeBid(this, bidAmount); // Notify mediator of the bid
39 | }
40 |
41 | // Receives notification of another bidder's action
42 | void receiveBidNotification(string bidderName, int bidAmount) override {
43 | cout << name << " received notification that " << bidderName << " placed a bid of " << bidAmount << endl;
44 | }
45 |
46 | // Returns the name of the bidder
47 | string getName() override {
48 | return name;
49 | }
50 | };
51 |
52 | // Concrete implementation of the auction mediator
53 | class AuctionMediator : public IAuctionMediator {
54 | set bidders; // Collection of bidders participating in the auction
55 |
56 | public:
57 | // Constructor initializes an empty set of bidders
58 | AuctionMediator() {
59 | bidders.clear();
60 | }
61 |
62 | // Adds a new bidder to the collection
63 | void addBidder(IBidder *bidder) override {
64 | bidders.insert(bidder);
65 | }
66 |
67 | // Handles bid placement and notifies other bidders
68 | void placeBid(IBidder *bidder, int bidAmount) override {
69 | for (auto notifyBidder : bidders) {
70 | if (notifyBidder != bidder) { // Skip the bidder who placed the bid
71 | notifyBidder->receiveBidNotification(bidder->getName(), bidAmount);
72 | }
73 | }
74 | }
75 | };
76 |
77 | // Main function to demonstrate the Mediator Design Pattern
78 | int main() {
79 | // Create the auction mediator
80 | IAuctionMediator *auctionMediator = new AuctionMediator();
81 |
82 | // Create bidders and register them with the mediator
83 | IBidder *bidder1 = new Bidder("samyak", auctionMediator);
84 | IBidder *bidder2 = new Bidder("shreya", auctionMediator);
85 | IBidder *bidder3 = new Bidder("aishik", auctionMediator);
86 |
87 | // Place bids
88 | bidder1->placeBid(100); // Samyak places a bid
89 | cout << "--------------" << endl;
90 |
91 | bidder2->placeBid(200); // Shreya places a bid
92 | cout << "--------------" << endl;
93 |
94 | bidder3->placeBid(300); // Aishik places a bid
95 |
96 | // Clean up dynamically allocated memory
97 | delete bidder1;
98 | delete bidder2;
99 | delete bidder3;
100 | delete auctionMediator;
101 |
102 | return 0;
103 | }
104 |
105 |
106 |
--------------------------------------------------------------------------------
/behavioral-design-pattern/momento-design-pattern.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | using namespace std;
3 |
4 | // Memento Design Pattern:
5 | // The Memento Design Pattern is a behavioral design pattern that provides the ability to
6 | // restore an object to a previous state without revealing the details of the object’s
7 | // implementation. It is typically used to implement undo/redo mechanisms.
8 |
9 | // Memento Class
10 | // This class represents a snapshot of an object's state. It stores the height and width
11 | // values of the Originator and provides access to these values.
12 | class Momento {
13 | private:
14 | int height; // The height value to be stored.
15 | int width; // The width value to be stored.
16 |
17 | public:
18 | // Constructor to initialize the height and width values.
19 | Momento(int h, int w): height(h), width(w) {}
20 |
21 | /**
22 | * @brief Gets the stored height value.
23 | * @return The stored height.
24 | */
25 | int getHeight() {
26 | return height;
27 | }
28 |
29 | /**
30 | * @brief Gets the stored width value.
31 | * @return The stored width.
32 | */
33 | int getWidth() {
34 | return width;
35 | }
36 | };
37 |
38 | // Originator Class
39 | // This class represents the object whose state needs to be saved and restored.
40 | // It provides methods to create a Memento (snapshot of its current state) and restore
41 | // its state from a Memento.
42 | class Originator {
43 | private:
44 | int height; // Current height value.
45 | int width; // Current width value.
46 |
47 | public:
48 | // Constructor to initialize the height and width values.
49 | Originator(int h, int w): height(h), width(w) {}
50 |
51 | /**
52 | * @brief Sets the height value.
53 | * @param h The new height to set.
54 | */
55 | void setHeight(int h) {
56 | height = h;
57 | }
58 |
59 | /**
60 | * @brief Sets the width value.
61 | * @param w The new width to set.
62 | */
63 | void setWidth(int w) {
64 | width = w;
65 | }
66 |
67 | /**
68 | * @brief Gets the current height value.
69 | * @return The current height.
70 | */
71 | int getHeight() {
72 | return height;
73 | }
74 |
75 | /**
76 | * @brief Gets the current width value.
77 | * @return The current width.
78 | */
79 | int getWidth() {
80 | return width;
81 | }
82 |
83 | /**
84 | * @brief Creates a Memento containing the current state.
85 | * @return A pointer to the created Memento.
86 | */
87 | Momento* createMomento() {
88 | return new Momento(height, width);
89 | }
90 |
91 | /**
92 | * @brief Restores the state from a given Memento.
93 | * @param momento The Memento to restore the state from.
94 | */
95 | void restoreMomento(Momento *momento) {
96 | height = momento->getHeight();
97 | width = momento->getWidth();
98 | }
99 | };
100 |
101 | // Caretaker Class
102 | // This class is responsible for storing and managing Mementos. It provides methods
103 | // to add a Memento to the history and undo the last state by retrieving a Memento.
104 | class CareTaker {
105 | private:
106 | stack history; // Stack to maintain the history of Mementos.
107 |
108 | public:
109 | // Constructor to initialize the CareTaker.
110 | CareTaker() {
111 | while (!history.empty()) {
112 | history.pop();
113 | }
114 | }
115 |
116 | /**
117 | * @brief Adds a Memento to the history stack.
118 | * @param momento The Memento to add.
119 | */
120 | void addMomento(Momento *momento) {
121 | history.push(momento);
122 | }
123 |
124 | /**
125 | * @brief Retrieves and removes the last Memento from the history stack.
126 | * @return The last Memento, or NULL if the stack is empty.
127 | */
128 | Momento* undo() {
129 | if (history.empty()) {
130 | return NULL;
131 | }
132 | Momento *momento = history.top();
133 | history.pop();
134 | return momento;
135 | }
136 | };
137 |
138 | // Main function
139 | // Demonstrates the use of the Memento Design Pattern. The Originator's state is saved
140 | // as Mementos and restored using the CareTaker.
141 | int main() {
142 | // Create a CareTaker and an Originator with initial dimensions.
143 | CareTaker *careTaker = new CareTaker();
144 | Originator *originator = new Originator(25, 15);
145 |
146 | // Display the initial state.
147 | cout << "Height is " << originator->getHeight() << " and Width is " << originator->getWidth() << endl;
148 |
149 | // Save the initial state as a snapshot.
150 | Momento *snapshot1 = originator->createMomento();
151 | careTaker->addMomento(snapshot1);
152 |
153 | // Change the state of the Originator.
154 | originator->setHeight(15);
155 | originator->setWidth(25);
156 | cout << "Height is " << originator->getHeight() << " and Width is " << originator->getWidth() << endl;
157 |
158 | // Save the new state as another snapshot.
159 | Momento *snapshot2 = originator->createMomento();
160 | careTaker->addMomento(snapshot2);
161 |
162 | // Change the state of the Originator again.
163 | originator->setHeight(50);
164 | originator->setWidth(50);
165 | cout << "Height is " << originator->getHeight() << " and Width is " << originator->getWidth() << endl;
166 |
167 | // Undo to the previous state using the last saved snapshot.
168 | Momento *restoreStateMomento1 = careTaker->undo();
169 | originator->restoreMomento(restoreStateMomento1);
170 | cout << "Height is " << originator->getHeight() << " and Width is " << originator->getWidth() << endl;
171 |
172 | // Undo to the initial state using the first saved snapshot.
173 | Momento *restoreStateMomento2 = careTaker->undo();
174 | originator->restoreMomento(restoreStateMomento2);
175 | cout << "Height is " << originator->getHeight() << " and Width is " << originator->getWidth() << endl;
176 | }
177 |
--------------------------------------------------------------------------------
/behavioral-design-pattern/observer-design-pattern.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | using namespace std;
3 |
4 | // Forward declaration of StocksObservable class
5 | class StocksObservable;
6 |
7 | // Interface for observers that need to be notified
8 | class NotifyAlertObserver {
9 | public:
10 | // Pure virtual function to update observer with changes from the observable
11 | virtual void update(StocksObservable* observable) = 0;
12 | };
13 |
14 | // Interface for observables that notify observers
15 | class StocksObservable {
16 | public:
17 | // Pure virtual function to add an observer to the observable's list
18 | virtual void add(NotifyAlertObserver *observer) = 0;
19 |
20 | // Pure virtual function to remove an observer from the observable's list
21 | virtual void remove(NotifyAlertObserver *observer) = 0;
22 |
23 | // Pure virtual function to notify all observers of changes
24 | virtual void notify() = 0;
25 |
26 | // Pure virtual function to set the stock count
27 | virtual void setStockCount(int stock) = 0;
28 |
29 | // Pure virtual function to get the current stock count
30 | virtual int getStockCount() = 0;
31 | };
32 |
33 | // Concrete implementation of StocksObservable for iPhone stocks
34 | class IphoneStocksObservable: public StocksObservable {
35 | private:
36 | set observerList; // List of observers to notify
37 | int stockCount; // Current stock count
38 |
39 | public:
40 | // Constructor initializes the observer list and stock count
41 | IphoneStocksObservable() {
42 | observerList.clear();
43 | stockCount = 0;
44 | }
45 |
46 | // Adds an observer to the list
47 | void add(NotifyAlertObserver *observer) {
48 | observerList.insert(observer);
49 | }
50 |
51 | // Removes an observer from the list
52 | void remove(NotifyAlertObserver *observer) {
53 | observerList.erase(observer);
54 | }
55 |
56 | // Notifies all observers of stock changes
57 | void notify() {
58 | for(NotifyAlertObserver* observer: observerList) {
59 | observer->update(this);
60 | }
61 | }
62 |
63 | // Sets the stock count and notifies observers if the previous stock count was zero
64 | void setStockCount(int stock) {
65 | if(stockCount == 0) {
66 | stockCount = stock;
67 | notify();
68 | }
69 | else {
70 | stockCount = stock;
71 | }
72 | }
73 |
74 | // Returns the current stock count
75 | int getStockCount() {
76 | return stockCount;
77 | }
78 | };
79 |
80 | // Concrete implementation of StocksObservable for Samsung stocks
81 | class SamsungStocksObservable: public StocksObservable {
82 | private:
83 | set observerList; // List of observers to notify
84 | int stockCount; // Current stock count
85 |
86 | public:
87 | // Constructor initializes the observer list and stock count
88 | SamsungStocksObservable() {
89 | observerList.clear();
90 | stockCount = 0;
91 | }
92 |
93 | // Adds an observer to the list
94 | void add(NotifyAlertObserver *observer) {
95 | observerList.insert(observer);
96 | }
97 |
98 | // Removes an observer from the list
99 | void remove(NotifyAlertObserver *observer) {
100 | observerList.erase(observer);
101 | }
102 |
103 | // Notifies all observers of stock changes
104 | void notify() {
105 | for(NotifyAlertObserver* observer: observerList) {
106 | observer->update(this);
107 | }
108 | }
109 |
110 | // Sets the stock count and notifies observers if the previous stock count was zero
111 | void setStockCount(int stock) {
112 | if(stockCount == 0) {
113 | stockCount = stock;
114 | notify();
115 | }
116 | else {
117 | stockCount = stock;
118 | }
119 | }
120 |
121 | // Returns the current stock count
122 | int getStockCount() {
123 | return stockCount;
124 | }
125 | };
126 |
127 | // Concrete implementation of NotifyAlertObserver for mobile alerts
128 | class MobileAlertObserver: public NotifyAlertObserver {
129 | private:
130 | string username; // User's name for alerting
131 |
132 | public:
133 | // Constructor initializes the observer with the user's name
134 | MobileAlertObserver(string un) {
135 | username = un;
136 | }
137 |
138 |
139 | // Updates the observer with the stock count and sends an alert
140 | void update(StocksObservable* observable) {
141 | cout << observable->getStockCount() << " sent to " << username << endl;
142 | }
143 | };
144 |
145 | // Concrete implementation of NotifyAlertObserver for email alerts
146 | class EmailAlertObserver: public NotifyAlertObserver {
147 | private:
148 | string email; // User's email for alerting
149 |
150 | public:
151 | // Constructor initializes the observer with the user's email
152 | EmailAlertObserver(string em) {
153 | email = em;
154 | }
155 |
156 | // Updates the observer with the stock count and sends an email alert
157 | void update(StocksObservable* observable) {
158 | cout << observable->getStockCount() << " sent to " << email << endl;
159 | }
160 | };
161 |
162 | // Main function demonstrating the observer pattern
163 | int main() {
164 | // Creating observables for iPhone and Samsung stocks
165 | StocksObservable *iphoneStocksObservable = new IphoneStocksObservable();
166 | StocksObservable *samsungStocksObservable = new SamsungStocksObservable();
167 |
168 | // Creating observers for mobile and email alerts
169 | NotifyAlertObserver *observer1 = new MobileAlertObserver("samyak");
170 | NotifyAlertObserver *observer2 = new MobileAlertObserver("shreya");
171 | NotifyAlertObserver *observer3 = new EmailAlertObserver("Aishik@gamil.com");
172 |
173 | // Adding observers to observables
174 | iphoneStocksObservable->add(observer1);
175 | iphoneStocksObservable->add(observer2);
176 | iphoneStocksObservable->add(observer3);
177 | samsungStocksObservable->add(observer3);
178 |
179 | // Setting stock counts which will trigger notifications to observers
180 | iphoneStocksObservable->setStockCount(10);
181 | samsungStocksObservable->setStockCount(5);
182 | }
183 |
--------------------------------------------------------------------------------
/behavioral-design-pattern/state-design-pattern.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/samyakmehta28/Low-Level-Design-Patterns/7f2d43d338fd8c6b95b80208592c6b962bd9d4b2/behavioral-design-pattern/state-design-pattern.png
--------------------------------------------------------------------------------
/behavioral-design-pattern/strategy-design-pattern.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | using namespace std;
3 |
4 | // The Strategy Design Pattern allows you to encapsulate various driving behaviors
5 | // and apply them dynamically to different vehicles. The Vehicle class uses a reference
6 | // to a DriveStrategy object, allowing it to perform different driving actions based on
7 | // the strategy assigned. This design promotes flexibility and scalability, making it
8 | // easy to add new driving strategies or modify existing ones without changing the
9 | // Vehicle class.
10 |
11 | // Abstract Strategy Class
12 | // This class defines the interface for various driving strategies. Each specific driving
13 | // strategy (e.g., SportDrive, NormalDrive) will implement the `drive` method.
14 | class DriveStrategy {
15 | public:
16 | // Pure virtual function, which will be implemented by concrete strategies.
17 | virtual void drive() = 0;
18 | virtual ~DriveStrategy() = default; // Virtual destructor for proper cleanup of derived classes.
19 | };
20 |
21 | // Concrete Strategy for Sports vehicles
22 | // This strategy implements the `drive` function for driving in sport mode, emphasizing
23 | // high speed and sharp handling.
24 | class SportDrive : public DriveStrategy {
25 | public:
26 | // Implements the drive function for SportDrive strategy.
27 | void drive() override {
28 | cout << "Driving in Sport mode: High speed, sharp handling!" << endl;
29 | }
30 | };
31 |
32 | // Concrete Strategy for Normal vehicles
33 | // This strategy implements the `drive` function for driving in a normal mode, offering
34 | // a balanced speed and comfort.
35 | class NormalDrive : public DriveStrategy {
36 | public:
37 | // Implements the drive function for NormalDrive strategy.
38 | void drive() override {
39 | cout << "Driving in Normal mode: Balanced speed and comfort." << endl;
40 | }
41 | };
42 |
43 | // Concrete Strategy for Passenger vehicles
44 | // This strategy implements the `drive` function for driving in passenger mode, focusing
45 | // on a smooth and comfortable ride.
46 | class PassengerDrive : public DriveStrategy {
47 | public:
48 | // Implements the drive function for PassengerDrive strategy.
49 | void drive() override {
50 | cout << "Driving in Passenger mode: Smooth and comfortable ride." << endl;
51 | }
52 | };
53 |
54 | // Vehicle class
55 | // This class represents a vehicle that can change its driving strategy dynamically.
56 | // It holds a reference to a DriveStrategy and delegates the driving behavior to the strategy.
57 | class Vehicle {
58 | protected:
59 | DriveStrategy* driveStrategy; // Pointer to the current driving strategy
60 |
61 | public:
62 | // Constructor that initializes the vehicle with a specific driving strategy.
63 | Vehicle(DriveStrategy* strategy) : driveStrategy(strategy) {}
64 |
65 | // Method to change the current driving strategy dynamically.
66 | void setDriveStrategy(DriveStrategy* strategy) {
67 | driveStrategy = strategy;
68 | }
69 |
70 | // Method to perform the drive operation, delegating to the current strategy.
71 | void performDrive() {
72 | driveStrategy->drive();
73 | }
74 |
75 | // Destructor to clean up the strategy object to prevent memory leaks.
76 | virtual ~Vehicle() {
77 | delete driveStrategy; // Cleanup the strategy object when the Vehicle is destroyed.
78 | }
79 | };
80 |
81 | // SportsVehicle class
82 | // This class represents a specific type of vehicle, the sports car. It initializes
83 | // the vehicle with the SportDrive strategy by default.
84 | class SportsVehicle : public Vehicle {
85 | public:
86 | // Constructor for SportsVehicle, initializes with the SportDrive strategy.
87 | SportsVehicle() : Vehicle(new SportDrive()) {}
88 | };
89 |
90 | // Main function
91 | int main() {
92 | // Create a sports vehicle (car) with the SportDrive strategy.
93 | Vehicle* sportCar = new SportsVehicle();
94 |
95 | // Perform the drive action, which delegates the behavior to the current strategy.
96 | sportCar->performDrive(); // Output: "Driving in Sport mode: High speed, sharp handling!"
97 |
98 | // Optionally, you can change the driving strategy dynamically.
99 | // sportCar->setDriveStrategy(new NormalDrive());
100 | // sportCar->performDrive(); // Output: "Driving in Normal mode: Balanced speed and comfort."
101 |
102 | // Clean up allocated memory.
103 | delete sportCar;
104 | }
105 |
--------------------------------------------------------------------------------
/behavioral-design-pattern/template-design-pattern.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | using namespace std;
3 |
4 | // Template Method Design Pattern: The base class (IPayment) defines the structure
5 | // of the algorithm (sending money), while subclasses define specific steps (how to
6 | // validate requests, calculate fees, debit, and credit amounts for different payment types).
7 |
8 | // Abstract Base Class defining the template method
9 | class IPayment {
10 | public:
11 | // Template method defining the skeleton of the algorithm
12 | // The 'sendMoney' method is final, ensuring it can't be overridden by subclasses.
13 | // It calls the common steps in a fixed order.
14 | virtual void sendMoney() final {
15 | validateRequest(); // Step 1
16 | calculateFees(); // Step 2
17 | debitAmount(); // Step 3
18 | creditAmount(); // Step 4
19 | }
20 |
21 | // These are the abstract methods that must be implemented by subclasses
22 | virtual void validateRequest() = 0;
23 | virtual void calculateFees() = 0;
24 | virtual void debitAmount() = 0;
25 | virtual void creditAmount() = 0;
26 | };
27 |
28 | // Subclass for sending money to a friend
29 | class PayToFriend : public IPayment {
30 | public:
31 | void validateRequest() override {
32 | cout << "Validate Request for Pay to friend" << endl;
33 | }
34 |
35 | void calculateFees() override {
36 | cout << "Calculate fees for Pay to friend" << endl;
37 | }
38 |
39 | void debitAmount() override {
40 | cout << "Debit amount for Pay to friend" << endl;
41 | }
42 |
43 | void creditAmount() override {
44 | cout << "Credit amount for Pay to friend" << endl;
45 | }
46 | };
47 |
48 | // Subclass for sending money to a merchant
49 | class PayToMerch : public IPayment {
50 | public:
51 | void validateRequest() override {
52 | cout << "Validate Request for Pay to Merch" << endl;
53 | }
54 |
55 | void calculateFees() override {
56 | cout << "Calculate fees for Pay to Merch" << endl;
57 | }
58 |
59 | void debitAmount() override {
60 | cout << "Debit amount for Pay to Merch" << endl;
61 | }
62 |
63 | void creditAmount() override {
64 | cout << "Credit amount for Pay to Merch" << endl;
65 | }
66 | };
67 |
68 | int main() {
69 | // Create an instance of PayToFriend
70 | IPayment* payToFriend = new PayToFriend();
71 | // Calling the template method to execute the payment process
72 | payToFriend->sendMoney();
73 |
74 | cout << "----------------------" << endl;
75 |
76 | // Create an instance of PayToMerch
77 | IPayment* payToMerch = new PayToMerch();
78 | // Calling the template method to execute the payment process
79 | payToMerch->sendMoney();
80 | }
81 |
--------------------------------------------------------------------------------
/behavioral-design-pattern/visitor-design-pattern.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | using namespace std;
3 |
4 | // Visitor Design Pattern: The pattern allows separating operations (like pricing or maintenance)
5 | // from the classes (rooms) that the operations are performed on. It provides a way to define new
6 | // operations without modifying the classes of the elements.
7 |
8 | class SingleRoom; // Forward declaration
9 | class DoubleRoom; // Forward declaration
10 | class DeluxRoom; // Forward declaration
11 |
12 | // Abstract Visitor class defining the visit methods for different room types
13 | class RoomVisitor {
14 | public:
15 | virtual void visit(SingleRoom *singleRoom) = 0; // Visit single room
16 | virtual void visit(DoubleRoom *doubleRoom) = 0; // Visit double room
17 | virtual void visit(DeluxRoom *deluxRoom) = 0; // Visit deluxe room
18 | };
19 |
20 | // Abstract Element class with the accept method
21 | class RoomElement {
22 | public:
23 | virtual void accept(RoomVisitor *visitor) = 0; // Accept visitor
24 | };
25 |
26 | // Concrete Element class for a single room
27 | class SingleRoom : public RoomElement {
28 | public:
29 | int roomPrice = 1000; // Price of a single room
30 | void accept(RoomVisitor *visitor) override {
31 | visitor->visit(this); // Accept a visitor and call its visit method
32 | }
33 | };
34 |
35 | // Concrete Element class for a double room
36 | class DoubleRoom : public RoomElement {
37 | public:
38 | int roomPrice = 2000; // Price of a double room
39 | void accept(RoomVisitor *visitor) override {
40 | visitor->visit(this); // Accept a visitor and call its visit method
41 | }
42 | };
43 |
44 | // Concrete Element class for a deluxe room
45 | class DeluxRoom : public RoomElement {
46 | public:
47 | int roomPrice = 3000; // Price of a deluxe room
48 | void accept(RoomVisitor *visitor) override {
49 | visitor->visit(this); // Accept a visitor and call its visit method
50 | }
51 | };
52 |
53 | // Concrete Visitor class for calculating the pricing of rooms
54 | class RoomPricingVisitor : public RoomVisitor {
55 | public:
56 | /**
57 | * Prints the price of a single room to the console.
58 | * @param singleRoom Pointer to a SingleRoom object
59 | */
60 | void visit(SingleRoom *singleRoom) override {
61 | cout << "Price for this single room is " << singleRoom->roomPrice << endl;
62 | }
63 |
64 | /**
65 | * Prints the price of a double room to the console.
66 | * @param doubleRoom Pointer to a DoubleRoom object
67 | */
68 | void visit(DoubleRoom *doubleRoom) override {
69 | cout << "Price for this double room is " << doubleRoom->roomPrice << endl;
70 |
71 | }
72 | /**
73 | * Prints the price of a deluxe room to the console.
74 | * @param deluxRoom Pointer to a DeluxRoom object
75 | */
76 |
77 | void visit(DeluxRoom *deluxRoom) override {
78 | cout << "Price for this deluxe room is " << deluxRoom->roomPrice << endl;
79 |
80 | }
81 | };
82 |
83 | // Concrete Visitor class for performing maintenance on rooms
84 | class RoomMaintainenceVisitor : public RoomVisitor {
85 | public:
86 | void visit(SingleRoom *singleRoom) override {
87 | cout << "Maintenance for this single room" << endl;
88 | }
89 | void visit(DoubleRoom *doubleRoom) override {
90 | cout << "Maintenance for this double room" << endl;
91 | }
92 | void visit(DeluxRoom *deluxRoom) override {
93 | cout << "Maintenance for this deluxe room" << endl;
94 | }
95 | };
96 |
97 | int main() {
98 | // Create instances of different room types
99 | SingleRoom *singleRoom = new SingleRoom();
100 | DoubleRoom *doubleRoom = new DoubleRoom();
101 | DeluxRoom *deluxRoom = new DeluxRoom();
102 |
103 | // Create instances of different visitors (Room Pricing and Room Maintenance)
104 | RoomVisitor *roomPricingVisitor = new RoomPricingVisitor();
105 | RoomVisitor *roomMaintainenceVisitor = new RoomMaintainenceVisitor();
106 |
107 | // Accept visitors to perform operations
108 | singleRoom->accept(roomPricingVisitor); // Pricing for single room
109 | doubleRoom->accept(roomPricingVisitor); // Pricing for double room
110 | deluxRoom->accept(roomPricingVisitor); // Pricing for deluxe room
111 |
112 | cout << "-----------------" << endl;
113 |
114 | // Accept maintenance visitor to perform operations
115 | singleRoom->accept(roomMaintainenceVisitor); // Maintenance for single room
116 | doubleRoom->accept(roomMaintainenceVisitor); // Maintenance for double room
117 | deluxRoom->accept(roomMaintainenceVisitor); // Maintenance for deluxe room
118 |
119 | return 0;
120 | }
121 |
122 |
123 |
--------------------------------------------------------------------------------
/creational-design-pattern/builder-design-pattern.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | using namespace std;
3 |
4 | // The Builder design pattern is a creational design pattern that allows for the step-by-step construction of complex objects.
5 | // It separates the construction of a complex object from its representation, allowing the same construction process to create different representations.
6 | // This pattern is especially useful when an object needs to be created with many optional parts or configurations.
7 |
8 | // The Builder design pattern helps in creating complex objects by encapsulating the construction process, making it easy to manage and extend.
9 |
10 | // The Decorator design pattern is a structural design pattern that allows for the dynamic addition of behavior to an object at runtime,
11 | // which is useful for adding new functionalities without altering the object itself.
12 |
13 | // Class declarations for the Student and StudentBuilder
14 | class Student; // Forward declaration of Student class to be used by the builder
15 |
16 | // Abstract Builder class for constructing a Student object step by step.
17 | class StudentBuilder{
18 | public:
19 | int rollNumber; // Holds the roll number of the student
20 | int age; // Holds the age of the student
21 | string name; // Holds the name of the student
22 | vectorsubjects; // Holds the list of subjects the student is enrolled in
23 |
24 | public:
25 | // Set the roll number for the student.
26 | // Returns a pointer to the current StudentBuilder instance to allow method chaining.
27 | StudentBuilder* setRollNumber(int rn){
28 | this->rollNumber = rn;
29 | return this; // Returns the current instance for method chaining.
30 | }
31 |
32 | // Set the age for the student.
33 | // Returns a pointer to the current StudentBuilder instance to allow method chaining.
34 | StudentBuilder* setAge(int ag){
35 | this->age = ag;
36 | return this; // Returns the current instance for method chaining.
37 | }
38 |
39 | // Set the name for the student.
40 | // Returns a pointer to the current StudentBuilder instance to allow method chaining.
41 | StudentBuilder* setName(string nm){
42 | this->name = nm;
43 | return this; // Returns the current instance for method chaining.
44 | }
45 |
46 | // Abstract method that will be implemented by concrete builder classes to set the student's subjects.
47 | virtual StudentBuilder* setSubjects() = 0;
48 |
49 | // Method to construct the final Student object using the values set so far.
50 | // Returns a pointer to a newly constructed Student object.
51 | Student *buildStudent();
52 | };
53 |
54 | // Class representing the Student object.
55 | class Student{
56 | private:
57 | int rollNumber; // Student's roll number
58 | int age; // Student's age
59 | string name; // Student's name
60 | vectorsubjects; // Subjects that the student is enrolled in
61 |
62 | public:
63 | // Constructor that initializes the Student object using the values set in the StudentBuilder.
64 | Student(StudentBuilder *studentBuilder){
65 | this->rollNumber = studentBuilder->rollNumber;
66 | this->age = studentBuilder->age;
67 | this->name = studentBuilder->name;
68 | this->subjects = studentBuilder->subjects;
69 | }
70 |
71 | // Method to print the details of the student.
72 | void printStudentDetails(){
73 | cout<<"---------------------------------"<subjects.push_back("DSA"); // Data Structures and Algorithms
100 | this->subjects.push_back("Computer Networks"); // Computer Networks
101 | return this; // Returns the current instance for method chaining.
102 | }
103 | };
104 |
105 | // Concrete builder for MBA students, sets specific subjects for MBA students.
106 | class MBAStudentBuilder : public StudentBuilder{
107 | public:
108 | // Implementation of setSubjects method for MBA students.
109 | // Adds subjects that are typically taken by MBA students.
110 | StudentBuilder* setSubjects(){
111 | this->subjects.push_back("Finance"); // Finance
112 | this->subjects.push_back("Banking"); // Banking
113 | return this; // Returns the current instance for method chaining.
114 | }
115 | };
116 |
117 | // Main function to demonstrate the Builder design pattern.
118 | int main() {
119 | // Creating an EngineeringStudentBuilder object for an Engineering student.
120 | StudentBuilder *studentBuilder1 = new EngineeringStudentBuilder();
121 |
122 | // Setting the details for the first student (Engineering student) using method chaining.
123 | // Then building the final student object and printing the student details.
124 | Student *student = studentBuilder1->setRollNumber(94)
125 | ->setAge(22)
126 | ->setName("Samyak")
127 | ->setSubjects() // Setting subjects specific to Engineering students.
128 | ->buildStudent();
129 | student->printStudentDetails(); // Printing the details of the Engineering student.
130 |
131 | // Creating an MBAStudentBuilder object for an MBA student.
132 | StudentBuilder *studentBuilder2 = new MBAStudentBuilder();
133 |
134 | // Setting the details for the second student (MBA student) using method chaining.
135 | // Then building the final student object and printing the student details.
136 | student = studentBuilder2->setRollNumber(95)
137 | ->setAge(22)
138 | ->setName("Shreya")
139 | ->setSubjects() // Setting subjects specific to MBA students.
140 | ->buildStudent();
141 | student->printStudentDetails(); // Printing the details of the MBA student.
142 | }
143 |
--------------------------------------------------------------------------------
/creational-design-pattern/factory-design-pattern.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | using namespace std;
3 |
4 | // The Factory Pattern is a creational design pattern that provides an interface for creating objects in a superclass,
5 | // but allows subclasses to alter the type of objects that will be created. Below is an example of how you can implement the Factory Pattern
6 | // in C++ to create different types of shapes like Circle, Square, and Rectangle.
7 |
8 | // Abstract class Shape, representing a generic shape.
9 | class Shape {
10 | public:
11 | virtual void draw() = 0; // Pure virtual function to draw the shape, which must be implemented by derived classes.
12 | };
13 |
14 | // Concrete class Circle that inherits from Shape and implements the draw method.
15 | class Circle: public Shape {
16 | public:
17 | void draw() {
18 | cout << "circle" << endl; // Draw the circle by printing "circle".
19 | }
20 | };
21 |
22 | // Concrete class Rectangle that inherits from Shape and implements the draw method.
23 | class Rectangle: public Shape {
24 | public:
25 | void draw() {
26 | cout << "rectangle" << endl; // Draw the rectangle by printing "rectangle".
27 | }
28 | };
29 |
30 | // Concrete class Square that inherits from Shape and implements the draw method.
31 | class Square: public Shape {
32 | public:
33 | void draw() {
34 | cout << "square" << endl; // Draw the square by printing "square".
35 | }
36 | };
37 |
38 | // Factory class responsible for creating shapes based on input.
39 | class ShapeFactory {
40 | public:
41 | // The getShape method returns a pointer to a Shape object based on the string input.
42 | Shape *getShape(string shape) {
43 | Shape* ans;
44 | if(shape == "CIRCLE") {
45 | ans = new Circle(); // If input is "CIRCLE", create a Circle object.
46 | } else if(shape == "RECTANGLE") {
47 | ans = new Rectangle(); // If input is "RECTANGLE", create a Rectangle object.
48 | } else {
49 | ans = new Square(); // If input is anything else, create a Square object.
50 | }
51 | return ans; // Return the created Shape object.
52 | }
53 | };
54 |
55 | int main() {
56 | // Main function to demonstrate the Factory Pattern.
57 |
58 | ShapeFactory *shapeFactory = new ShapeFactory(); // Create a ShapeFactory object.
59 |
60 | // Get a Rectangle object by passing "RECTANGLE" as input to the factory.
61 | Shape* shape = shapeFactory->getShape("RECTANGLE");
62 |
63 | // Call the draw method of the created shape (Rectangle in this case).
64 | shape->draw(); // Output: "rectangle"
65 |
66 | return 0;
67 | }
68 |
--------------------------------------------------------------------------------
/creational-design-pattern/singleton-design-pattern.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | using namespace std;
3 |
4 | // Singleton Design Pattern: ensures only one instance of a class is created and provides a global access point to that instance.
5 |
6 | // Eager Initialization
7 | class EagerDBConnect {
8 | private:
9 | EagerDBConnect() {}; // Private constructor to prevent instantiation.
10 | static EagerDBConnect* eagerDBConnect; // Static instance, eagerly created when the program starts.
11 |
12 | public:
13 | // Static method to get the instance of EagerDBConnect.
14 | static EagerDBConnect* getDBConnection() {
15 | return eagerDBConnect; // Return the already created instance.
16 | }
17 |
18 | // Method to print a message indicating eager initialization.
19 | void print() {
20 | cout << "Eager Initialization" << endl;
21 | }
22 | };
23 |
24 | // Static initialization outside the class.
25 | EagerDBConnect* EagerDBConnect::eagerDBConnect = new EagerDBConnect();
26 |
27 | // Lazy Initialization
28 | class LazyDBConnect {
29 | private:
30 | LazyDBConnect() {}; // Private constructor to prevent instantiation.
31 | static LazyDBConnect* lazyDBConnect; // Static pointer that will be initialized when first needed.
32 |
33 | public:
34 | // Static method to get the instance of LazyDBConnect.
35 | static LazyDBConnect* getDBConnection() {
36 | if (lazyDBConnect == NULL) {
37 | lazyDBConnect = new LazyDBConnect(); // Instance created only when needed (lazily).
38 | }
39 | return lazyDBConnect; // Return the instance.
40 | }
41 |
42 | // Method to print a message indicating lazy initialization.
43 | void print() {
44 | cout << "Lazy Initialization" << endl;
45 | }
46 | };
47 |
48 | // Static initialization outside the class.
49 | LazyDBConnect* LazyDBConnect::lazyDBConnect = NULL;
50 |
51 | // Double-Checked Locking Singleton (Thread-Safe)
52 | mutex mtx; // Mutex for thread synchronization, ensuring only one thread can create the instance at a time.
53 |
54 | class DoubleLockingDBConnect {
55 | private:
56 | DoubleLockingDBConnect() {}; // Private constructor to prevent instantiation.
57 | static DoubleLockingDBConnect* doubleLockingDBConnect; // Static pointer to hold the single instance.
58 |
59 | public:
60 | // Static method to get the instance of DoubleLockingDBConnect.
61 | static DoubleLockingDBConnect* getDBConnection() {
62 | if (doubleLockingDBConnect == NULL) { // First check if the instance is not created yet.
63 | mtx.lock(); // Lock to ensure only one thread enters the critical section.
64 | if (doubleLockingDBConnect == NULL) { // Double check to prevent race condition.
65 | doubleLockingDBConnect = new DoubleLockingDBConnect(); // Create the instance.
66 | }
67 | mtx.unlock(); // Unlock after instance creation.
68 | }
69 | return doubleLockingDBConnect; // Return the instance.
70 | }
71 |
72 | // Method to print a message indicating double-checked locking initialization.
73 | void print() {
74 | cout << "Double Locking Initialization" << endl;
75 | }
76 | };
77 |
78 | // Static initialization outside the class.
79 | DoubleLockingDBConnect* DoubleLockingDBConnect::doubleLockingDBConnect = NULL;
80 |
81 | int main() {
82 | // Creating and testing the EagerDBConnect singleton.
83 | EagerDBConnect* eagerdbConnection = EagerDBConnect::getDBConnection();
84 | eagerdbConnection->print(); // Print message for eager initialization.
85 |
86 | // Creating and testing the LazyDBConnect singleton.
87 | LazyDBConnect* lazyDBConnect = LazyDBConnect::getDBConnection();
88 | lazyDBConnect->print(); // Print message for lazy initialization.
89 |
90 | // Creating and testing the DoubleLockingDBConnect singleton.
91 | DoubleLockingDBConnect* doubleLockingDBConnect = DoubleLockingDBConnect::getDBConnection();
92 | doubleLockingDBConnect->print(); // Print message for double-locking initialization.
93 | }
94 |
95 |
--------------------------------------------------------------------------------
/structural-design-pattern/adapter-design-pattern.cpp:
--------------------------------------------------------------------------------
1 | // The Adapter Design Pattern is a structural design pattern that allows objects with incompatible interfaces to work together.
2 | // It acts as a bridge between two incompatible interfaces by converting the interface of a class into another interface that a client expects.
3 |
4 | #include
5 | using namespace std;
6 |
7 | // Abstract class representing the Adaptee interface.
8 | // This class defines the method `getWeightInPounds`, which is expected to be implemented by concrete Adaptee classes.
9 | class WeighingMachineAdaptee {
10 | public:
11 | /**
12 | * @brief Returns the weight in pounds.
13 | *
14 | * This pure virtual function is meant to be overridden by concrete implementations
15 | * to provide the weight in pounds.
16 | * @return Weight in pounds.
17 | */
18 | virtual int getWeightInPounds() = 0;
19 | };
20 |
21 | // Concrete implementation of the Adaptee class.
22 | // This class represents a weighing machine that provides weight in pounds.
23 | class WeighingMachineInPounds: public WeighingMachineAdaptee {
24 | private:
25 | int value; // Stores the weight in pounds.
26 |
27 | public:
28 | /**
29 | * @brief Constructor for WeighingMachineInPounds.
30 | *
31 | * Initializes the weight value in pounds.
32 | * @param val The weight in pounds.
33 | */
34 | WeighingMachineInPounds(int val) : value(val) {};
35 |
36 | /**
37 | * @brief Returns the weight in pounds.
38 | *
39 | * Implements the Adaptee interface's method.
40 | * @return Weight in pounds.
41 | */
42 | int getWeightInPounds() {
43 | return value;
44 | };
45 | };
46 |
47 | // Abstract class representing the Adapter interface.
48 | // This class defines the method `getWeightInKilos`, which is expected to be implemented by concrete Adapter classes.
49 | class WeighingMachineAdapter {
50 | public:
51 | /**
52 | * @brief Returns the weight in kilograms.
53 | *
54 | * This pure virtual function is meant to be overridden by concrete implementations
55 | * to provide the weight in kilograms.
56 | * @return Weight in kilograms.
57 | */
58 | virtual double getWeightInKilos() = 0;
59 | };
60 |
61 | // Concrete implementation of the Adapter class.
62 | // This class adapts the WeighingMachineInPounds class to provide weight in kilograms.
63 | class WeighingMachineInKilos: public WeighingMachineAdapter {
64 | private:
65 | WeighingMachineAdaptee *weighingMachineInPounds; // Pointer to the Adaptee object.
66 |
67 | public:
68 | /**
69 | * @brief Constructor for WeighingMachineInKilos.
70 | *
71 | * Creates an instance of WeighingMachineInPounds with the given weight in pounds.
72 | * @param val The weight in pounds to be adapted.
73 | */
74 | WeighingMachineInKilos(int val) : weighingMachineInPounds(new WeighingMachineInPounds(val)) {};
75 |
76 | /**
77 | * @brief Returns the weight in kilograms.
78 | *
79 | * Converts the weight from pounds to kilograms using the formula:
80 | * 1 pound = 0.45 kilograms.
81 | * @return Weight in kilograms.
82 | */
83 | double getWeightInKilos() {
84 | return weighingMachineInPounds->getWeightInPounds() * 0.45;
85 | };
86 | };
87 |
88 | // Main function demonstrating the Adapter Design Pattern.
89 | // It creates a WeighingMachineInKilos object to adapt the WeighingMachineInPounds class
90 | // and prints the weight in kilograms.
91 | int main() {
92 | // Create an adapter object to convert weight from pounds to kilograms.
93 | WeighingMachineInKilos *weighingMachineInKilos = new WeighingMachineInKilos(20);
94 |
95 | // Print the weight in kilograms.
96 | cout << weighingMachineInKilos->getWeightInKilos() << endl;
97 |
98 | return 0;
99 | }
100 |
101 |
--------------------------------------------------------------------------------
/structural-design-pattern/bridge-design-pattern.cpp:
--------------------------------------------------------------------------------
1 | // The Bridge design pattern is a structural pattern used to decouple an abstraction from its implementation
2 | // so that the two can vary independently. This pattern is particularly useful when you want to avoid a permanent
3 | // binding between an abstraction and its implementation, which can help in extending both independently.
4 |
5 | #include
6 | using namespace std;
7 |
8 | // Abstract Implementor: Defines the interface for the breathing process that concrete implementations must follow.
9 | class BreathImplementor {
10 | public:
11 | /**
12 | * @brief Pure virtual function to define the breathing process.
13 | *
14 | * Concrete classes will implement the breathing logic.
15 | */
16 | virtual void breathprocess() = 0;
17 | };
18 |
19 | // Concrete Implementor: Provides a specific breathing process for land-dwelling entities.
20 | class LandBreathImpl: public BreathImplementor {
21 | public:
22 | /**
23 | * @brief Implements breathing for land-dwelling entities.
24 | */
25 | void breathprocess() {
26 | cout << "Land Breathing" << endl;
27 | }
28 | };
29 |
30 | // Concrete Implementor: Provides a specific breathing process for water-dwelling entities.
31 | class WaterBreathImpl: public BreathImplementor {
32 | public:
33 | /**
34 | * @brief Implements breathing for water-dwelling entities.
35 | */
36 | void breathprocess() {
37 | cout << "Water Breathing" << endl;
38 | }
39 | };
40 |
41 | // Abstraction: Represents a generic living thing that delegates its breathing process to an implementor.
42 | class LivingThing {
43 | protected:
44 | BreathImplementor *breathImplementor; // Pointer to a breathing implementor (Bridge).
45 |
46 | public:
47 | /**
48 | * @brief Constructor for LivingThing.
49 | *
50 | * Initializes the LivingThing with a specific breathing implementor.
51 | * @param bi Pointer to a BreathImplementor object.
52 | */
53 | LivingThing(BreathImplementor *bi): breathImplementor(bi) {};
54 |
55 | /**
56 | * @brief Pure virtual function to define the breathing process for a living thing.
57 | */
58 | virtual void breathprocess() = 0;
59 | };
60 |
61 | // Refined Abstraction: Represents a Dog, which is a land-dwelling living thing.
62 | class Dog: public LivingThing {
63 | public:
64 | /**
65 | * @brief Constructor for Dog.
66 | *
67 | * Initializes the Dog with a specific breathing implementor.
68 | * @param bi Pointer to a BreathImplementor object.
69 | */
70 | Dog(BreathImplementor *bi): LivingThing(bi) {};
71 |
72 | /**
73 | * @brief Implements the breathing process for a Dog.
74 | */
75 | void breathprocess() {
76 | cout << "Breath process for Dog: " << endl;
77 | breathImplementor->breathprocess();
78 | }
79 | };
80 |
81 | // Refined Abstraction: Represents a Fish, which is a water-dwelling living thing.
82 | class Fish: public LivingThing {
83 | public:
84 | /**
85 | * @brief Constructor for Fish.
86 | *
87 | * Initializes the Fish with a specific breathing implementor.
88 | * @param bi Pointer to a BreathImplementor object.
89 | */
90 | Fish(BreathImplementor *bi): LivingThing(bi) {};
91 |
92 | /**
93 | * @brief Implements the breathing process for a Fish.
94 | */
95 | void breathprocess() {
96 | cout << "Breath process for Fish: " << endl;
97 | breathImplementor->breathprocess();
98 | }
99 | };
100 |
101 | // Main function demonstrating the Bridge Design Pattern.
102 | // It shows how different living things can independently use different breathing implementors.
103 | int main() {
104 | // Create a Fish object using a WaterBreathImpl.
105 | LivingThing *fish = new Fish(new WaterBreathImpl());
106 | fish->breathprocess();
107 |
108 | // Create a Dog object using a LandBreathImpl.
109 | LivingThing *dog = new Dog(new LandBreathImpl());
110 | dog->breathprocess();
111 |
112 | return 0;
113 | }
114 |
--------------------------------------------------------------------------------
/structural-design-pattern/composite-design-pattern.cpp:
--------------------------------------------------------------------------------
1 | // The Composite Design Pattern is a structural design pattern that allows you to compose objects
2 | // into tree-like structures to represent part-whole hierarchies. It lets clients treat individual
3 | // objects and compositions of objects uniformly. This is particularly useful when you want to
4 | // represent a hierarchy of objects where individual objects and their containers are treated the same way.
5 |
6 | #include
7 | using namespace std;
8 |
9 | // Abstract Base Class: Represents the common interface for both individual objects (Files)
10 | // and composite objects (Directories).
11 | class FileSystem {
12 | public:
13 | /**
14 | * @brief Lists the contents of the file system.
15 | */
16 | virtual void ls() = 0;
17 |
18 | /**
19 | * @brief Adds a file system component to the current object.
20 | *
21 | * For files, this operation is not supported.
22 | * For directories, this operation allows adding files or subdirectories.
23 | */
24 | virtual void add(FileSystem* fs) = 0;
25 |
26 | // Virtual destructor to ensure proper cleanup of derived objects.
27 | virtual ~FileSystem() {}
28 | };
29 |
30 | // Leaf Class: Represents individual objects (Files) in the hierarchy.
31 | class File : public FileSystem {
32 | private:
33 | string name; // Name of the file.
34 |
35 | public:
36 | /**
37 | * @brief Constructor for File.
38 | *
39 | * @param nm Name of the file.
40 | */
41 | File(string nm) : name(nm) {}
42 |
43 | /**
44 | * @brief Lists the file name.
45 | */
46 | void ls() {
47 | cout << "File: " << name << endl;
48 | }
49 |
50 | /**
51 | * @brief Throws an exception as adding components to a file is not allowed.
52 | *
53 | * @param fs Pointer to a file system component.
54 | */
55 | void add(FileSystem* fs) {
56 | throw runtime_error("Cannot add to a file");
57 | }
58 | };
59 |
60 | // Composite Class: Represents composite objects (Directories) that can contain Files or other Directories.
61 | class Directory : public FileSystem {
62 | private:
63 | string name; // Name of the directory.
64 | vector content; // Vector to store child components (Files and Directories).
65 |
66 | public:
67 | /**
68 | * @brief Constructor for Directory.
69 | *
70 | * @param nm Name of the directory.
71 | */
72 | Directory(string nm) : name(nm) {}
73 |
74 | /**
75 | * @brief Adds a file system component (File or Directory) to the directory.
76 | *
77 | * @param fileSystem Pointer to a file system component.
78 | */
79 | void add(FileSystem* fileSystem) {
80 | content.push_back(fileSystem);
81 | }
82 |
83 | /**
84 | * @brief Lists the directory name and its contents.
85 | */
86 | void ls() {
87 | cout << "Directory: " << name << endl;
88 | for (auto fileSystem : content) {
89 | fileSystem->ls();
90 | }
91 | }
92 |
93 | /**
94 | * @brief Destructor to clean up dynamically allocated child components.
95 | */
96 | ~Directory() {
97 | for (auto fileSystem : content) {
98 | delete fileSystem;
99 | }
100 | }
101 | };
102 |
103 | // Main function demonstrating the Composite Design Pattern.
104 | // It shows how a directory can contain files and subdirectories in a tree-like structure.
105 | int main() {
106 | // Create a root directory.
107 | FileSystem* root = new Directory("root");
108 |
109 | // Create a file and add it to the root directory.
110 | FileSystem* mainFile = new File("main.ts");
111 | root->add(mainFile);
112 |
113 | // Create a subdirectory named "src".
114 | FileSystem* src = new Directory("src");
115 |
116 | // Create a file and add it to the "src" directory.
117 | FileSystem* appFile = new File("app.ts");
118 | src->add(appFile);
119 |
120 | // Add the "src" directory to the root directory.
121 | root->add(src);
122 |
123 | // List the contents of the root directory.
124 | root->ls();
125 |
126 | // Clean up dynamically allocated objects.
127 | delete root;
128 |
129 | return 0;
130 | }
131 |
132 |
133 |
134 |
--------------------------------------------------------------------------------
/structural-design-pattern/decorator-design-pattern.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | using namespace std;
3 |
4 | // The Decorator Design Pattern is a structural design pattern that allows behavior
5 | // to be added to individual objects, either statically or dynamically, without
6 | // affecting the behavior of other objects from the same class.
7 |
8 | /// Abstract Component: Defines the interface for pizzas.
9 | class BasePizza {
10 | public:
11 | virtual int cost() = 0; // Method to calculate the cost of the pizza.
12 | virtual ~BasePizza() {} // Virtual destructor for proper cleanup.
13 | };
14 |
15 | /// Abstract Decorator: Serves as a base class for all decorators.
16 | class ToppingDecorator : public BasePizza {
17 | // No additional members. Extends the BasePizza interface.
18 | };
19 |
20 | /// Concrete Component: Represents a basic Hand Tossed pizza.
21 | class HandTossed : public BasePizza {
22 | public:
23 | int cost() override {
24 | return 100; // Base cost of Hand Tossed pizza.
25 | }
26 | };
27 |
28 | /// Concrete Component: Represents a Thin Crust pizza.
29 | class ThinCrust : public BasePizza {
30 | public:
31 | int cost() override {
32 | return 150; // Base cost of Thin Crust pizza.
33 | }
34 | };
35 |
36 | /// Concrete Decorator: Adds Mushroom topping.
37 | class Mushroom : public ToppingDecorator {
38 | private:
39 | BasePizza* pizza; // The pizza being decorated.
40 | public:
41 | Mushroom(BasePizza* piz) : pizza(piz) {}
42 | int cost() override {
43 | return pizza->cost() + 10; // Add cost of Mushroom topping.
44 | }
45 | };
46 |
47 | /// Concrete Decorator: Adds Cheese topping.
48 | class Cheese : public ToppingDecorator {
49 | private:
50 | BasePizza* pizza; // The pizza being decorated.
51 | public:
52 | Cheese(BasePizza* piz) : pizza(piz) {}
53 | int cost() override {
54 | return pizza->cost() + 20; // Add cost of Cheese topping.
55 | }
56 | };
57 |
58 | /// Main function demonstrating the Decorator Design Pattern.
59 | int main() {
60 | // Start with a Thin Crust pizza.
61 | BasePizza* currPizza = new ThinCrust();
62 | cout << "Cost of Thin Crust: " << currPizza->cost() << endl;
63 |
64 | // Add Mushroom topping.
65 | currPizza = new Mushroom(currPizza);
66 | cout << "Cost after adding Mushroom: " << currPizza->cost() << endl;
67 |
68 | // Add Cheese topping.
69 | currPizza = new Cheese(currPizza);
70 | cout << "Cost after adding Cheese: " << currPizza->cost() << endl;
71 |
72 | // Cleanup: Avoid memory leaks.
73 | delete currPizza;
74 |
75 | return 0;
76 | }
77 |
--------------------------------------------------------------------------------
/structural-design-pattern/facade-design-pattern.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/samyakmehta28/Low-Level-Design-Patterns/7f2d43d338fd8c6b95b80208592c6b962bd9d4b2/structural-design-pattern/facade-design-pattern.png
--------------------------------------------------------------------------------
/structural-design-pattern/flyweight-design-pattern-with-singleton-concept.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | using namespace std;
3 |
4 | // FlyWeight Design Pattern:
5 | // The Flyweight design pattern is a structural design pattern aimed at reducing memory usage by sharing as much data as possible with similar objects.
6 | // This pattern is particularly useful when you need to create a large number of similar objects.
7 | // Instead of creating new objects for every instance, the Flyweight pattern reuses existing instances, minimizing memory footprint.
8 |
9 | // Abstract base class for letters.
10 | // This class provides a common interface for all letter objects.
11 | // The display method is a pure virtual function that derived classes must implement.
12 | class ILetter {
13 | public:
14 | /**
15 | * @brief Displays the letter at the given position.
16 | *
17 | * This method is a pure virtual function that will be implemented by derived classes.
18 | * @param x The x-coordinate where the letter will be displayed.
19 | * @param y The y-coordinate where the letter will be displayed.
20 | */
21 | virtual void display(int x, int y) = 0;
22 | };
23 |
24 | // Concrete implementation of the ILetter interface.
25 | // This class represents a document character with properties like character, font type, and font size.
26 | class DocumentCharacter : public ILetter {
27 | private:
28 | char character; // The character to be displayed.
29 | string fontType; // The font type of the character.
30 | int fontSize; // The font size of the character.
31 |
32 | public:
33 | /**
34 | * @brief Constructor for DocumentCharacter.
35 | *
36 | * Initializes a character with the given font type and size.
37 | * @param c The character to be created.
38 | * @param ft The font type of the character.
39 | * @param fs The font size of the character.
40 | */
41 | DocumentCharacter(char c, string ft, int fs) : character(c), fontType(ft), fontSize(fs) {}
42 |
43 | /**
44 | * @brief Displays the character at the specified position.
45 | *
46 | * Prints the character and its position on the console.
47 | * @param x The x-coordinate where the character is displayed.
48 | * @param y The y-coordinate where the character is displayed.
49 | */
50 | void display(int x, int y) {
51 | cout << character << " at " << x << ' ' << y << endl;
52 | }
53 | };
54 |
55 | // Singleton Factory class for creating and managing letter objects.
56 | // This class ensures that only one instance of itself exists and reuses existing letter objects to minimize memory usage.
57 | class LetterFactory {
58 | private:
59 | static LetterFactory *letterFactory; // Singleton instance of LetterFactory.
60 | map cache; // Cache to store already created letter objects.
61 |
62 | /**
63 | * @brief Private constructor for LetterFactory.
64 | *
65 | * Ensures that no objects of LetterFactory can be created directly.
66 | */
67 | LetterFactory() {}
68 |
69 | public:
70 | /**
71 | * @brief Retrieves the singleton instance of LetterFactory.
72 | *
73 | * @return The singleton instance of LetterFactory.
74 | */
75 | static LetterFactory *getLetterFactory() {
76 | return letterFactory;
77 | }
78 |
79 | /**
80 | * @brief Creates or retrieves a letter object.
81 | *
82 | * If the requested letter already exists in the cache, it is returned.
83 | * Otherwise, a new letter object is created, added to the cache, and returned.
84 | * @param character The character for which a letter object is requested.
85 | * @param fontType The font type of the letter.
86 | * @param fontSize The font size of the letter.
87 | * @return A pointer to the letter object.
88 | */
89 | ILetter *createLetter(char character, string fontType, int fontSize) {
90 | // Check if the letter already exists in the cache.
91 | if (cache.find(character) == cache.end()) {
92 | cout << "Creating new Letter " << character << endl;
93 | ILetter *iLetter = new DocumentCharacter(character, fontType, fontSize);
94 | cache[character] = iLetter; // Store the newly created letter in the cache.
95 | }
96 | return cache[character]; // Return the cached letter.
97 | }
98 | };
99 |
100 | // Initialize the static singleton instance.
101 | LetterFactory* LetterFactory::letterFactory = new LetterFactory();
102 |
103 | /**
104 | * @brief Main function to demonstrate the Flyweight Design Pattern.
105 | *
106 | * This function uses the LetterFactory to create and reuse letter objects.
107 | * Letters with the same character are created only once and reused multiple times, showcasing the memory efficiency of the Flyweight pattern.
108 | */
109 | int main() {
110 | // Get the singleton instance of LetterFactory.
111 | LetterFactory *letterFactory1 = LetterFactory::getLetterFactory();
112 |
113 | // Create and display letters using the first instance of LetterFactory.
114 | ILetter *letter1 = letterFactory1->createLetter('t', "sans", 16);
115 | letter1->display(0, 0);
116 | ILetter *letter2 = letterFactory1->createLetter('h', "sans", 16);
117 | letter2->display(0, 1);
118 | ILetter *letter3 = letterFactory1->createLetter('a', "sans", 16);
119 | letter3->display(0, 2);
120 | ILetter *letter4 = letterFactory1->createLetter('t', "sans", 16);
121 | letter4->display(0, 3);
122 |
123 | cout << "---------------------------------" << endl;
124 |
125 | // Get the singleton instance of LetterFactory again to demonstrate reuse.
126 | LetterFactory *letterFactory2 = LetterFactory::getLetterFactory();
127 |
128 | // Create and display letters using the second instance of LetterFactory.
129 | ILetter *letter5 = letterFactory2->createLetter('t', "sans", 16);
130 | letter5->display(0, 0);
131 | ILetter *letter6 = letterFactory2->createLetter('h', "sans", 16);
132 | letter6->display(0, 1);
133 | ILetter *letter7 = letterFactory2->createLetter('i', "sans", 16);
134 | letter7->display(0, 2);
135 | ILetter *letter8 = letterFactory2->createLetter('s', "sans", 16);
136 | letter8->display(0, 3);
137 | }
138 |
--------------------------------------------------------------------------------
/structural-design-pattern/flyweight-design-pattern.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | using namespace std;
3 |
4 | // FlyWeight Design Pattern:
5 | // The Flyweight design pattern is a structural design pattern aimed at reducing memory usage by sharing as much data as possible with similar objects.
6 | // It reuses existing instances instead of creating new ones for every instance, which minimizes memory footprint.
7 |
8 | // Abstract interface for a letter.
9 | // This interface enforces a contract for all letter types to implement the `display` method.
10 | class ILetter {
11 | public:
12 | /**
13 | * @brief Displays the letter at the given coordinates.
14 | *
15 | * @param x The x-coordinate where the letter will be displayed.
16 | * @param y The y-coordinate where the letter will be displayed.
17 | */
18 | virtual void display(int x, int y) = 0;
19 | };
20 |
21 | // Concrete implementation of the ILetter interface.
22 | // This class represents a specific letter with properties like font type and size.
23 | class DocumentCharacter : public ILetter {
24 | private:
25 | char character; // The character to be displayed.
26 | string fontType; // Font type of the character.
27 | int fontSize; // Font size of the character.
28 |
29 | public:
30 | /**
31 | * @brief Constructor to initialize a DocumentCharacter.
32 | *
33 | * @param c The character to create.
34 | * @param ft The font type of the character.
35 | * @param fs The font size of the character.
36 | */
37 | DocumentCharacter(char c, string ft, int fs) : character(c), fontType(ft), fontSize(fs) {}
38 |
39 | /**
40 | * @brief Displays the character at the given coordinates.
41 | *
42 | * Prints the character and its position.
43 | * @param x The x-coordinate where the character is displayed.
44 | * @param y The y-coordinate where the character is displayed.
45 | */
46 | void display(int x, int y) {
47 | cout << character << " at " << x << ' ' << y << endl;
48 | }
49 | };
50 |
51 | // Factory class to manage creation and reuse of letter objects.
52 | // Uses a static `cache` to store already created letters and ensures reuse.
53 | class LetterFactory {
54 | private:
55 | static map cache; // Cache to store created letters.
56 |
57 | public:
58 | /**
59 | * @brief Creates or retrieves a letter object.
60 | *
61 | * Checks the cache to see if the requested letter already exists.
62 | * If not, creates a new letter, stores it in the cache, and returns it.
63 | * @param character The character to create or retrieve.
64 | * @param fontType The font type of the character.
65 | * @param fontSize The font size of the character.
66 | * @return A pointer to the letter object.
67 | */
68 | static ILetter* createLetter(char character, string fontType, int fontSize) {
69 | // Check if the character already exists in the cache.
70 | if (cache.find(character) == cache.end()) {
71 | cout << "Creating new Letter " << character << endl;
72 | ILetter* iLetter = new DocumentCharacter(character, fontType, fontSize);
73 | cache[character] = iLetter; // Store the new letter in the cache.
74 | }
75 | return cache[character]; // Return the cached letter.
76 | }
77 | };
78 |
79 | // Initialize the static cache.
80 | map LetterFactory::cache = {};
81 |
82 | /**
83 | * @brief Main function demonstrating the Flyweight Design Pattern.
84 | *
85 | * Creates and reuses letter objects using the LetterFactory. The Flyweight pattern ensures that
86 | * letters with the same character are created only once and reused, showcasing memory efficiency.
87 | */
88 | int main() {
89 | // Create and display letters using the LetterFactory.
90 | ILetter* letter1 = LetterFactory::createLetter('t', "sans", 16);
91 | letter1->display(0, 0);
92 |
93 | ILetter* letter2 = LetterFactory::createLetter('h', "sans", 16);
94 | letter2->display(0, 1);
95 |
96 | ILetter* letter3 = LetterFactory::createLetter('a', "sans", 16);
97 | letter3->display(0, 2);
98 |
99 | // Reuse the previously created letter 't'.
100 | ILetter* letter4 = LetterFactory::createLetter('t', "sans", 16);
101 | letter4->display(0, 3);
102 |
103 | return 0;
104 | }
105 |
--------------------------------------------------------------------------------
/structural-design-pattern/proxy-design-pattern.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | using namespace std;
3 |
4 | // The Proxy Design Pattern is a structural design pattern that provides a surrogate or placeholder
5 | // for another object to control access to it. This pattern is useful for access restriction, caching,
6 | // pre- or post-processing, and other scenarios where direct access to an object is expensive or unsafe.
7 |
8 | // Class representing an Employee with an ID and name.
9 | class Employee {
10 | public:
11 | int employeeId; // Employee ID.
12 | string employeeName; // Employee Name.
13 |
14 | // Default constructor.
15 | Employee() = default;
16 |
17 | // Parameterized constructor to initialize an employee object.
18 | Employee(int eid, string eName) : employeeId(eid), employeeName(eName) {}
19 | };
20 |
21 | // Abstract class defining the Employee Database interface.
22 | // This serves as the base class for both the concrete implementation and the proxy.
23 | class EmployeeDB {
24 | public:
25 | /**
26 | * @brief Create a new employee record.
27 | * @param client The client attempting the operation.
28 | * @param employee The employee object to be added.
29 | */
30 | virtual void create(string client, Employee employee) = 0;
31 |
32 | /**
33 | * @brief Retrieve an employee's name by ID.
34 | * @param client The client attempting the operation.
35 | * @param employeeId The ID of the employee to retrieve.
36 | * @return The name of the employee.
37 | */
38 | virtual string get(string client, int employeeId) = 0;
39 | };
40 |
41 | // Concrete implementation of the Employee Database interface.
42 | // Stores employee records in a map for efficient retrieval.
43 | class EmployeeDBImpl : public EmployeeDB {
44 | private:
45 | map db; // Map storing Employee objects indexed by employeeId.
46 |
47 | public:
48 | // Constructor initializes the database.
49 | EmployeeDBImpl() {
50 | db.clear();
51 | }
52 |
53 | // Adds a new employee to the database.
54 | void create(string client, Employee employee) override {
55 | db[employee.employeeId] = employee;
56 | }
57 |
58 | // Retrieves an employee's name by their ID.
59 | string get(string client, int employeeId) override {
60 | if (db.find(employeeId) == db.end()) {
61 | throw runtime_error("No user found"); // Handle case where employeeId is not in the database.
62 | }
63 | return db[employeeId].employeeName;
64 | }
65 | };
66 |
67 | // Proxy class for the Employee Database.
68 | // Controls access to the actual `EmployeeDBImpl` by checking client permissions.
69 | class EmployeeDBProxy : public EmployeeDB {
70 | private:
71 | EmployeeDB* employeeDBImpl; // The real EmployeeDB implementation.
72 |
73 | public:
74 | // Constructor initializes the proxy with an instance of the real database implementation.
75 | EmployeeDBProxy() : employeeDBImpl(new EmployeeDBImpl()) {}
76 |
77 | // Destructor to clean up dynamically allocated memory.
78 | ~EmployeeDBProxy() {
79 | delete employeeDBImpl;
80 | }
81 |
82 | // Adds a new employee record if the client is "ADMIN".
83 | void create(string client, Employee employee) override {
84 | if (client == "ADMIN") {
85 | employeeDBImpl->create(client, employee);
86 | return;
87 | }
88 | throw runtime_error("Access denied"); // Non-admin clients cannot create records.
89 | }
90 |
91 | // Retrieves an employee's name if the client is "ADMIN" or "USER".
92 | string get(string client, int employeeId) override {
93 | if (client == "ADMIN" || client == "USER") {
94 | return employeeDBImpl->get(client, employeeId);
95 | }
96 | throw runtime_error("Access denied"); // Other clients cannot retrieve records.
97 | }
98 | };
99 |
100 | int main() {
101 | // Create a proxy for the Employee Database.
102 | EmployeeDB* employeeDBProxy = new EmployeeDBProxy();
103 |
104 | // Create an employee object.
105 | Employee employee1(1, "Samyak");
106 |
107 | try {
108 | // Admin creates a new employee record.
109 | employeeDBProxy->create("ADMIN", employee1);
110 |
111 | // User retrieves the employee record.
112 | cout << employeeDBProxy->get("USER", 1) << endl;
113 |
114 | } catch (const exception& e) {
115 | cerr << "Caught exception: " << e.what() << endl; // Handle exceptions gracefully.
116 | }
117 |
118 | // Clean up dynamically allocated memory.
119 | delete employeeDBProxy;
120 |
121 | return 0;
122 | }
123 |
--------------------------------------------------------------------------------