├── .gitignore ├── BDP-ChainOfResponsibilityPatter └── README.md ├── BDP-CommandPattern └── README.md ├── BDP-IteratorPattern └── README.md ├── BDP-MementoPatten └── README.md ├── BDP-StrategyPattern └── code │ ├── example-1.ts │ ├── package-lock.json │ ├── package.json │ └── tsconfig.json ├── CDP-BuilderPattern └── README.md ├── CDP-PrototypePattern └── README.md ├── Object-Oriented-Programming └── UML-CheetSheet.md ├── README.md ├── SDP-AdapterPattern └── README.md ├── SDP-DecoratorPattern └── code │ ├── example-1.ts │ ├── example-2.ts │ ├── package-lock.json │ ├── package.json │ └── tsconfig.json ├── SDP-FlyweightPattern └── README.md ├── UML.MD └── tsconfig.json /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ -------------------------------------------------------------------------------- /BDP-ChainOfResponsibilityPatter/README.md: -------------------------------------------------------------------------------- 1 |

2 |

Chain of responsibility Pattern

3 |

4 | 5 | > The Chain of Responsibility is a behavioral design pattern that allows you to create a chain of objects, where each object has the ability to handle a certain type of request or task. The request is passed through the chain until it is handled by an appropriate handler or until the end of the chain is reached. 6 | 7 | In essence, it let's you pass requests along a chain of handlers; Upon receiving a request, each handler decides either to process the request or to pass it to the next handler in the chain. 8 | 9 | *** 10 | 11 | ### The easiest way to understand the intent of the Chain of Responsibility pattern is to look at examples of where it is useful. 12 | 13 | Imagine an organization where employees can submit leave requests, and these requests need to be approved at different levels of authority. The Chain of Responsibility pattern can be used to model this scenario. 14 | 15 | The Chain of Responsibility pattern is particularly suitable when certain conditions or requirements align with its characteristics. Here are scenarios in which you might prefer to use the Chain of Responsibility pattern over other design patterns: 16 | 17 | 1. **Dynamic Handling Logic:** 18 | When the handling logic is subject to change or configuration at runtime, the Chain of Responsibility pattern excels. It allows you to dynamically assemble and modify the sequence of handlers, accommodating changing business rules or requirements. 19 | 20 | 2. **Multiple Possible Handlers:** 21 | If there are multiple potential handlers for a request, and you want to ensure that one or more of them can process the request, the Chain of Responsibility is a good fit. This is especially useful in scenarios where the processing responsibilities might differ for different cases. 22 | 23 | 4. **Single Responsibility Principle:** 24 | If you aim to adhere to the Single Responsibility Principle by separating the handling logic into individual handler classes, the Chain of Responsibility is appropriate. This prevents handlers from becoming bloated with unrelated code. 25 | 26 | 5. **Flexible Error Handling:** 27 | In situations where you need to provide multiple levels of error handling or exception processing, the Chain of Responsibility can offer a structured way to handle different types of errors at different levels of the chain. 28 | 29 | 6. **Avoiding Large Switch Statements:** 30 | If you're dealing with a large number of potential cases or conditions that would lead to a cumbersome if-else or switch statement, using the Chain of Responsibility can lead to cleaner and more maintainable code. 31 | 32 | 7. **Hierarchical Processing:** 33 | When requests need to be processed hierarchically or in a specific order, the Chain of Responsibility pattern allows you to create a sequence of handlers that reflect the desired order of processing. 34 | 35 | 8. **Implementing Middleware Pipelines:** 36 | In applications that involve processing pipelines, such as web frameworks, the Chain of Responsibility can be used to implement middleware layers that perform various tasks on incoming requests or outgoing responses. 37 | 38 | In essence, use the Chain of Responsibility pattern when you require a flexible, dynamic, and modular approach to handling requests, especially when you expect changes or extensions in the handling logic. It's particularly valuable in scenarios where you want to avoid tight coupling, manage complex branching, or separate responsibilities into distinct components. 39 | 40 | #### How it works 41 | * When a request is made, it is passed to the first handler in the chain. 42 | * The handler examines the request and decides whether it can handle it or not. Along with processing the request, handlers pass the request further along the chain. 43 | * If the handler can handle the request, it processes the request and completes the task. 44 | * If the handler cannot handle the request, it passes the request to the next handler in the chain. 45 | * This process continues until a handler is found that can handle the request or until the end of the chain is reached. ( The request travels along the chain until all handler had the chance to process it ) 46 | * In some variations, A handler can decide not to pass the request further down the chain and effectively stop any further processing. So it's either one handler that process the request or none at all. 47 | 48 | *** 49 | 50 | ### Steps to implementing the adapter pattern. 51 | 52 | > **AGENDA** : The chain of responsibility relies on transforming particular behaviors into stand-alone objects called **handlers**. The pattern suggests you link these handlers to a chain, this is done by designing the handler interface such that it has a field for storing a reference to the next handler in the chain. Once we chain these handlers we can streamline processing of the request. 53 | > 54 | > * Provides flexibility to dynamically change the chain or add new handlers without affecting the client code. 55 | > * Supports open/closed principle by allowing new handlers to be added without modifying existing code. 56 | 57 | 58 | 1. We start by identifying the *Request*, in this case A leave request represents a request for taking time off. 59 | ```TS 60 | interface LeaveRequest { 61 | days: number; 62 | employee: string; 63 | } 64 | ``` 65 | 66 | 2. Then we identify the interface of the **Handler**, A Handler in this case represent different levels of authority for approving leave requests. For example, there could be handlers for team leads, managers, and HR. Each handler knows if it can approve the request or if it should pass it to the next handler. The interface should have a field to store reference to the next handler. 67 | ```TS 68 | // 69 | abstract class LeaveHandler { 70 | protected nextHandler: LeaveHandler | null = null; 71 | 72 | setNextHandler(handler: LeaveHandler): void { 73 | this.nextHandler = handler; 74 | } 75 | 76 | abstract handleRequest(request: LeaveRequest): void; 77 | } 78 | 79 | class TeamLead extends LeaveHandler { 80 | handleRequest(request: LeaveRequest): void { 81 | if (request.days <= 2) { 82 | console.log(`Team Lead approved ${request.days} days leave for ${request.employee}`); 83 | } else if (this.nextHandler) { 84 | this.nextHandler.handleRequest(request); 85 | } 86 | } 87 | } 88 | 89 | class Manager extends LeaveHandler { 90 | handleRequest(request: LeaveRequest): void { 91 | if (request.days <= 5) { 92 | console.log(`Manager approved ${request.days} days leave for ${request.employee}`); 93 | } else if (this.nextHandler) { 94 | this.nextHandler.handleRequest(request); 95 | } 96 | } 97 | } 98 | 99 | class HR extends LeaveHandler { 100 | handleRequest(request: LeaveRequest): void { 101 | console.log(`HR approved ${request.days} days leave for ${request.employee}`); 102 | } 103 | } 104 | ``` 105 | 106 | 3. The **chain** consists of handlers linked in a specific order of authority. The request is passed from one handler to another until it is approved or rejected. 107 | ```TS 108 | const teamLead = new TeamLead(); 109 | const manager = new Manager(); 110 | const hr = new HR(); 111 | 112 | teamLead.setNextHandler(manager); 113 | manager.setNextHandler(hr); 114 | ``` 115 | 116 | 4. The **Client** passes the request to the first handler in the chain. 117 | ```TS 118 | const leaveRequest: LeaveRequest = { days: 3, employee: "John" }; 119 | teamLead.handleRequest(leaveRequest); // Output: Manager approved 3 days leave for John 120 | ``` 121 | 122 | In this example, the Chain of Responsibility pattern helps ensure that the leave request is handled by the appropriate authority level, based on the number of days requested. 123 | 124 | *** 125 | 126 | ### Variations of Chain of Responsibility Pattern 127 | 128 | 1. **Chain Can Break:** 129 | In this variation, the primary goal is to ensure that the event or request goes through all the handlers in the chain. If a handler decides that it cannot handle the event (e.g., it rejects the event based on certain conditions), the chain is broken, and the event does not proceed further in the chain. This variation is useful when you want the event to follow a strict sequential path through the handlers. 130 | 131 | For example, consider a purchase approval process. The chain of handlers consists of different levels of authority, such as team leads, managers, and executives. If any handler in the chain rejects the purchase request, the approval process is halted, and the request is not forwarded to higher levels of authority. 132 | 133 | 2. **Non-Breaking Chain:** 134 | In this variation, the primary objective is to ensure that the event is processed by each handler in the chain, regardless of whether a handler rejects the event or not. Each handler performs its specific processing on the event, and the chain continues to the next handler in sequence. The idea here is to provide a uniform processing experience for each handler without breaking the chain. 135 | 136 | For instance, consider a logging system where events are passed through different logging handlers. Even if one handler determines that it cannot log the event due to a specific condition, the event still proceeds to subsequent handlers for their logging activities. 137 | 138 | 3. **Exclusive Handler Execution:** 139 | This variation focuses on a scenario where only one specific handler from the chain is allowed to execute the request. The chain of handlers may consist of various handlers, but only one handler is chosen to process the request based on certain criteria. Once the appropriate handler is found, it exclusively handles the event, and the chain is terminated. 140 | 141 | A real-world example could be a network communication system where incoming data packets need to be processed by a specific protocol handler based on the packet type. Once the suitable protocol handler is identified, it processes the packet according to the protocol's requirements. 142 | 143 | These variations offer flexibility in how the Chain of Responsibility pattern can be applied based on the requirements of your system. Depending on the context, you can choose whether the chain should break, continue non-breaking, or select a specific handler for exclusive execution of the request. Each variation caters to different scenarios and use cases, allowing you to design a chain of handlers that suits your specific needs. 144 | 145 | *** 146 | 147 | ### Advantages Over Conventional if-else / switch Statements: 148 | 149 | 1. **Open/Closed Principle:** 150 | The Chain of Responsibility pattern follows the Open/Closed Principle by allowing new handlers to be added without altering existing code. In contrast, adding new cases to if-else or switch statements can lead to changes in the existing code, violating this principle. 151 | 152 | 2. **Enhanced Flexibility:** 153 | The pattern offers greater flexibility by enabling the creation of complex, flexible, and dynamic chains of handlers. This is particularly useful in scenarios with intricate decision-making logic. 154 | 155 | 3. **Reduced Code Duplication:** 156 | The Chain of Responsibility pattern reduces code duplication by centralizing the handling logic within the handlers. This prevents the need to repeat similar conditional statements in multiple parts of the codebase. 157 | 158 | 4. **Simplification of Client Code:** 159 | Client code becomes cleaner and easier to read since it only needs to send the request to the first handler in the chain, without worrying about the details of each handler. 160 | 161 | 5. **Scalability and Reusability:** 162 | The pattern scales well as the number of handlers increases. It allows you to reuse existing handlers in different chains, enhancing code reusability. 163 | 164 | 6. **Easier Maintenance:** 165 | Changes to the handling logic can be isolated within individual handlers, reducing the risk of introducing bugs or affecting other parts of the application. 166 | 167 | Overall, the Chain of Responsibility pattern provides a more modular, flexible, and maintainable solution compared to both other design patterns and the traditional if-else or switch statement approach. It's particularly advantageous in scenarios where there is a need for multiple processing steps, complex decision-making, or a potential for future changes in the handling logic. 168 | 169 |

When to use Chain of responsibility pattern over other patterns

170 | 171 | The decision to use the Chain of Responsibility pattern over other design patterns depends on the specific characteristics of your application and the problem you're trying to solve. Here are scenarios where the Chain of Responsibility pattern might be more suitable than other design patterns: 172 | 173 | 1. **Command Pattern:** 174 | - Use Chain of Responsibility when you have multiple potential handlers for a request and you want to ensure that one or more of them can process it. 175 | - Chain of Responsibility is more focused on handling and passing requests, while the Command pattern emphasizes encapsulating actions as objects. 176 | - If you need dynamic assembly of handlers at runtime, Chain of Responsibility is a better choice. 177 | 178 | 2. **Strategy Pattern:** 179 | - Choose Chain of Responsibility when you need a sequence of handlers to process a request and you're concerned about dynamic order or selection of handlers. 180 | - Strategy focuses on encapsulating interchangeable algorithms, while Chain of Responsibility emphasizes the passing of requests through a chain of handlers. 181 | 182 | 3. **Interpreter Pattern:** 183 | - Choose Chain of Responsibility when you need a hierarchy of handlers to interpret or process different parts of a language or grammar. 184 | - Interpreter focuses on interpreting or evaluating expressions, while Chain of Responsibility focuses on handling requests. 185 | 186 | In general, choose the Chain of Responsibility pattern when your primary concern is to create a flexible, decoupled, and dynamic way of processing requests or events through a sequence of handlers. Consider other patterns when their core principles align more closely with your specific requirements. Remember that design patterns are tools to address specific problems, so the choice depends on the nature of the problem you're solving and the goals you're trying to achieve. 187 | -------------------------------------------------------------------------------- /BDP-CommandPattern/README.md: -------------------------------------------------------------------------------- 1 |

2 |

Command Pattern

3 |

4 | 5 | > The Command pattern creates objects to represent actions or requests, separating the sender from the performer of the action. This separation enhances flexibility in customization and supports features like queuing of actions and undo/redo functionality. It simplifies code, promotes reusability, and enables advanced features in applications. 6 | 7 | *** 8 | 9 | ### The easiest way to understand the intent of the Command pattern is to look at examples of where it is useful. 10 | 11 | **Example Scenario: Discord Bot Command Handling** 12 | 13 | Imagine you're the creator of a popular Discord bot that adds exciting features to servers. Users interact with your bot by sending messages, and you want to enhance their experience by introducing a range of slash commands, each triggering a specific action. To achieve this, you decide to apply the Command pattern. 14 | 15 | In this scenario, the Command pattern becomes a powerful tool for efficiently managing and executing user requests. Here's how it unfolds: 16 | 17 | **1. Command Objects for User Actions:** 18 | You define command objects for each distinct action your bot can perform. For instance, you create command classes like GreetCommand, PlayMusicCommand, FetchDataCommand, and so on. Each command class adheres to a common Command interface, requiring the implementation of an execute/run() method. 19 | 20 | **2. Bot Interaction with User Inputs:** 21 | When users send messages to the Discord server, your bot's command handling system processes the messages. It detects if a message contains a slash command (e.g., "/greet," "/play," "/fetch"), indicating the user's intended action. 22 | 23 | **3. Command Execution:** 24 | Upon identifying a command in the user's message, the bot's command handling system instantiates the corresponding command object. For example, if the user types "/greet," the system creates an instance of the GreetCommand class. 25 | 26 | **4. Execution and Response:** 27 | The bot executes the command by invoking its execute() method. This method performs the specific action associated with the command. For instance, the GreetCommand might send a friendly greeting to the user's server. 28 | 29 | **5. Flexible Extension and Maintenance:** 30 | New command classes can be added easily as your bot's capabilities expand. Whether it's introducing mini-games, searching the web, or managing server settings, each command is encapsulated within its class, promoting a clean and modular codebase. 31 | 32 | **6. Scalability and User Experience:** 33 | As your bot's functionality grows, the Command pattern ensures that the addition of new features doesn't complicate the overall structure. Each command is a self-contained unit, promoting code reusability and easing the integration of user-requested actions. 34 | 35 | **7. Undo/Redo and User Interaction:** 36 | By maintaining a history of executed commands, you're not only able to fulfill user requests but also provide undo and redo functionality. Users can reverse previous actions or reapply them, enhancing their interaction with your bot. 37 | 38 | In summary, the Command pattern empowers your Discord bot to handle user interactions seamlessly and dynamically. It encapsulates user actions as distinct command objects, simplifying the management of bot functionalities and allowing for easy expansion and enhancement. Whether it's welcoming users, playing music, or retrieving data, your bot's command handling system efficiently translates user intents into meaningful actions. 39 | 40 | *** 41 | 42 | ### Steps to implementing the command pattern. 43 | 44 | > **AGENDA** : Create execution of various actions within a software application, by encapsulating these actions as command objects, 45 | 46 | 1. **Define the Command Interface**: Create an interface called `Command` that defines the structure and behavior of command objects. This interface should include properties for command names, a help method, and a run method for executing the command. 47 | 48 | ```typescript 49 | export default interface Command { 50 | readonly commandNames: string[]; 51 | help(commandPrefix: string): string; 52 | run(parsedUserCommand: Message): Promise; 53 | } 54 | ``` 55 | 56 | 2. Implement **Concrete Command Classes** that implement the `Command` interface. Each class should define its specific command names, a help message, and the logic to execute the command. 57 | 58 | ```typescript 59 | export class GreetCommand implements Command { 60 | commandNames = ["greet", "hello"]; 61 | 62 | help(commandPrefix: string): string { 63 | return `Use ${commandPrefix}greet to get a greeting.`; 64 | } 65 | 66 | async run(message: Message): Promise { 67 | await message.reply("hello, User!"); 68 | } 69 | } 70 | 71 | export class TimeCommand implements Command { 72 | commandNames = ["time"]; 73 | 74 | help(commandPrefix: string): string { 75 | return `Use ${commandPrefix}time to get the current time.`; 76 | } 77 | 78 | async run(message: Message): Promise { 79 | const now = new Date(); 80 | await message.reply(`${now.getHours()} : ${now.getMinutes()}`); 81 | } 82 | } 83 | ``` 84 | 85 | 3. Create an **Invoker** or in our case Command Registry, set up a command registry to manage and map user commands to their corresponding command objects. This registry will aid in command execution and help provide consistent responses to users. 86 | 87 | ```typescript 88 | export class CommandRegistry { 89 | private commands: Map = new Map(); 90 | private history: Command[] = []; 91 | 92 | run(command: Command): void { 93 | command.run(); 94 | this.history.push(command); 95 | } 96 | } 97 | 98 | ``` 99 | 100 | 4. Create a **Client** in your application's logic, parse user input (e.g., messages or user commands) and use the command registry to retrieve and execute the corresponding command. 101 | 102 | ```typescript 103 | const registry = new CommandRegistry(); 104 | 105 | const greetCommand = new GreetCommand(); 106 | const timeCommand = new TimeCommand(); 107 | 108 | registry.run(timeCommand); 109 | registry.run(greetCommand); 110 | ``` 111 | 112 | *** 113 | 114 |

When to use Command pattern over other patterns

115 | 116 | Here are a few design patterns that are similar to the Command pattern, along with explanations of when to use the Command pattern over each of them: 117 | 118 | 1. **Strategy Pattern:** 119 | - Strategy Pattern defines a family of interchangeable algorithms, allowing clients to switch between different strategies without altering their code. 120 | - Use Command Pattern over Strategy Pattern when you want to encapsulate user actions as distinct objects, enabling undo/redo and command history management. 121 | - Similarity: Both patterns encapsulate behaviors in separate objects. 122 | - Applicability: Strategy Pattern is about selecting algorithms dynamically. Use Command Pattern when you need to encapsulate user actions as distinct executable commands. 123 | 124 | In summary, while these design patterns share some similarities with the Command pattern, the Command pattern provides a structured approach to managing user interactions in scenarios where user commands need to be treated as first-class objects in the application's design. 125 | 126 | -------------------------------------------------------------------------------- /BDP-IteratorPattern/README.md: -------------------------------------------------------------------------------- 1 |

2 |

Iterator Pattern

3 |

4 | 5 | > The iterator pattern is a behavioral design pattern that allows you to traverse a collection of objects without exposing its underlying representation. 6 | It's useful when you need to process complex data structures, such as lists or trees, in a specific way. This pattern helps you decouple the iteration logic from the data structure, making it easier to change the underlying structure without affecting the iteration logic. 7 | 8 | Think of the iterator pattern when you're working with complex data structures and need to iterate over them in a specific way, but you anticipate the way in which the data structured is composed my change. For example, when you're working with a large dataset and need to process each item in a specific order, you currently store these data structures as a list but in future you can use a graph based structure to store data. The entire system need not change because the data structure changes. 9 | 10 | *** 11 | 12 | ### The easiest way to understand the intent of the Iterator pattern is to look at examples of where it is useful. 13 | 14 | The iterator pattern is commonly used when working with a database, you might use an iterator to iterate over a large dataset without having to load the entire dataset into memory. 15 | 16 | Before we jump into a practical example it is necessary to understand why we need an iterator to traverse a complex data structure. 17 | 18 | **Decoupling / Improved maintainability / Abstraction / Flexibility:** The iterator is decoupled from the specific implementation of the data structure, making it easier to change the data structure or switch to a different implementation. We can store our data as an array or a linked list or anything else, it doesn't matter as the iterator provides an abstraction layer between the data structure and the code that uses the data, making it easier to switch between different implementations. As the iterator is responsible for traversing through the data and the rest of system is unaffected. The iterator makes it easier to modify or replace the data structure without affecting the code that uses the data. 19 | 20 | *** 21 | 22 | ### Here are the steps to implement the Iterator pattern: 23 | 24 | > **AGENDA** : Use the iterator pattern to hide the underlying representation of the collection/data, from the means of accessing the collection/data. Iterator pattern uses stand-alone objects called **iterators** which has methods for iterating over the data structure. 25 | > 26 | > * Provides flexibility to dynamically change the iterator or add new iterators without affecting the client code. 27 | > * Supports open/closed principle by allowing new iterators to be added without modifying existing code. 28 | 29 | first we understand the moving parts in the Iterator pattern: 30 | 31 | 1. **Aggregate**: This is the class that contains the data structure that needs to be iterated over. The Aggregate class provides a method to create an Iterator object. 32 | 33 | 2. **Iterator**: This is the class that implements the iteration logic. The Iterator class provides methods to iterate over the data structure, such as `hasNext()` and `next()`. 34 | 35 | 3. **Concrete Iterator**: This is a subclass of the Iterator class that is specific to the Aggregate class. The Concrete Iterator class provides the implementation of the iteration logic for the specific Aggregate class. 36 | 37 | 4. **Client**: This is the class that uses the Iterator pattern to iterate over the data structure. The Client class uses the Iterator object to iterate over the data structure. 38 | 39 | **Step 1: Define the Aggregate class:** 40 | 41 | * Create a class that contains the data structure that needs to be iterated over. 42 | * Define a method to create an Iterator object. 43 | 44 | ```typescript 45 | class Aggregate { 46 | private collection: T[]; 47 | 48 | constructor(collection: T[]) { 49 | this.collection = collection; 50 | } 51 | 52 | public iterator(): Iterator { 53 | return new Iterator(this.collection); 54 | } 55 | } 56 | ``` 57 | 58 | Step 2: Define the Iterator interface: 59 | 60 | * Create an interface that defines the methods for iterating over the data structure. 61 | * The methods should include `hasNext()` and `next()`. 62 | 63 | ```typescript 64 | interface Iterator { 65 | next(): T | undefined; 66 | hasNext(): boolean; 67 | remove(): void; 68 | } 69 | ``` 70 | 71 | Step 3: Define the Concrete Iterator class: 72 | 73 | * Create a subclass of the Iterator class that is specific to the Aggregate class. 74 | * Implement the iteration logic for the specific Aggregate class. 75 | 76 | ```typescript 77 | class MyIterator implements Iterator { 78 | private collection: T[]; 79 | private index: number; 80 | 81 | constructor(collection: T[]) { 82 | this.collection = collection; 83 | this.index = 0; 84 | } 85 | 86 | next(): T | undefined { 87 | if (!this.hasNext()) { 88 | return undefined; 89 | } 90 | const item = this.collection[this.index]; 91 | this.index++; 92 | return item; 93 | } 94 | 95 | hasNext(): boolean { 96 | return this.index < this.collection.length; 97 | } 98 | 99 | remove(): void { 100 | if (!this.hasNext()) { 101 | throw new Error("Cannot remove from an empty iterator"); 102 | } 103 | this.collection.splice(this.index - 1, 1); 104 | } 105 | } 106 | ``` 107 | 108 | Step 4: Implement the Aggregate class: 109 | 110 | * Implement the method to create an Iterator object. 111 | * Use the Concrete Iterator class to iterate over the data structure. 112 | 113 | ```typescript 114 | class MyAggregate { 115 | private collection: T[]; 116 | 117 | constructor(collection: T[]) { 118 | this.collection = collection; 119 | } 120 | 121 | public iterator(): MyIterator { 122 | return new MyIterator(this.collection); 123 | } 124 | } 125 | ``` 126 | 127 | Step 5: Implement the Client class: 128 | 129 | * Use the Iterator object to iterate over the data structure. 130 | * Use the `hasNext()` and `next()` methods to iterate over the data structur 131 | 132 | ```typescript 133 | const songs: Song[] = [ 134 | { name: 'Song 1' }, 135 | { name: 'Song 2' }, 136 | { name: 'Song 3' }, 137 | ]; 138 | 139 | const aggregate = new MyAggregate(songs); 140 | const iterator = aggregate.iterator(); 141 | while (iterator.hasNext()) { 142 | const song = iterator.next(); 143 | console.log(`Playing song: ${song.name}`); 144 | } 145 | ``` 146 | > In future if the data structure changes, a new **iterator** will need to be written specifically for the new **data structure** and be used in the **aggregate**, the client code will remain unchanged! 147 | 148 | *** 149 | 150 |

When to use Chain of responsibility pattern over other patterns

151 | 152 | There are other patterns that are similar to the Iterator pattern, including: 153 | 154 | 1. **Visitor pattern**: The Visitor pattern is similar to the Iterator pattern in that it allows you to traverse a data structure and perform operations on each element. However, the Visitor pattern is more focused on performing operations on each element, whereas the Iterator pattern is more focused on iterating over the data structure. 155 | 2. **Composite pattern**: The Composite pattern is similar to the Iterator pattern in that it allows you to compose objects together to form a new object. However, the Composite pattern is more focused on composing objects together to form a new object, whereas the Iterator pattern is more focused on iterating over a data structure. 156 | 3. **State pattern**: The State pattern is similar to the Iterator pattern in that it allows you to change the behavior of an object based on its state. However, the State pattern is more focused on changing the behavior of an object based on its state, whereas the Iterator pattern is more focused on iterating over a data structure. 157 | 158 | When to use the Iterator pattern over other patterns: 159 | 160 | 1. **Use the Iterator pattern when you need to iterate over a complex data structure**: If you need to iterate over a complex data structure, such as a graph or a tree, the Iterator pattern is a good choice. 161 | 2. **Use the Iterator pattern when you need to decouple the iteration logic from the data structure**: If you need to separate the iteration logic from the data structure, the Iterator pattern is a good choice. 162 | 3. **Use the Iterator pattern when you need to support multiple iteration protocols**: If you need to support multiple iteration protocols, such as iterating over a collection of objects or iterating over a stream of data, the Iterator pattern is a good choice. 163 | 164 | In summary, the Iterator pattern is a powerful tool for iterating over complex data structures and decoupling the iteration logic from the data structure. It is similar to other patterns, such as the Visitor pattern and the Composite pattern, but it is more focused on iterating over a data structure. 165 | 166 | 167 | 168 | -------------------------------------------------------------------------------- /BDP-MementoPatten/README.md: -------------------------------------------------------------------------------- 1 |

2 |

Memento Pattern

3 |

4 | 5 | > The Memento design pattern is used to capture the internal state of an object and externalize it so that it can be restored later. It is useful when you need to save the state of an object and restore it later, without exposing the internal state of the object. 6 | > 7 | > 8 | > You should think of the Memento pattern when you need to: 9 | > 10 | > * Save the state of an object and restore it later 11 | > * Implement undo/redo functionality 12 | > * Implement a "save" and "load" functionality for an object 13 | > * Implement a "snapshot" functionality for an object 14 | 15 | *** 16 | 17 | ### The easiest way to understand the intent of the Memento pattern is to look at examples of where it is useful. 18 | 19 | The Memento pattern is useful in applications that require saving and restoring the state of an object, such as: 20 | 21 | * Text editors that allow users to undo and redo changes 22 | * Games that allow players to save and load their progress 23 | * Chat applications that allow users to save and restore their chat history 24 | 25 | *** 26 | 27 | ### Steps to implementing the Memento pattern in TypeScript: 28 | 29 | Let's consider a scenario where we're building a "Digital Art Gallery" Museum; We wish to always have a snapshot of how the Museum looks, allowing the curator to "undo" a proposed change or "redo" a previous action. 30 | 31 | > **AGENDA**: Use the Memento pattern to save the state of each exhibit at each point in time and allow the curator to undo and redo their actions. 32 | 33 | 1. First we define the **Memento interface** that will hold the state of the object, this step is more of a prerequisite, Memento's usually have only 1 method `getState`. 34 | ```typescript 35 | interface Memento { 36 | getState(): any; 37 | } 38 | ``` 39 | 40 | 2. Then we add methods to our **Originator class** to **set/getState**, **set/restoreMemento**. The Originator class is the class whose state is to be saved. 41 | ```typescript 42 | class Exhibit { 43 | private state: any; 44 | 45 | setState(state: any) { 46 | this.state = state; 47 | } 48 | 49 | getState(): any { 50 | return this.state; 51 | } 52 | 53 | saveToMemento(): ExhibitMemento { 54 | return new ExhibitMemento(this.state); 55 | } 56 | 57 | restoreFromMemento(memento: ExhibitMemento) { 58 | this.state = memento.getState(); 59 | } 60 | } 61 | ``` 62 | 63 | 3. Next we create a concrete **Memento class** this class will store the state of the exhibit. 64 | ```typescript 65 | class ExhibitMemento { 66 | private state: any; 67 | 68 | constructor(state: any) { 69 | this.state = state; 70 | } 71 | 72 | getState(): any { 73 | return this.state; 74 | } 75 | } 76 | ``` 77 | 78 | 4. **Optional Step** is to **define the Caretaker class**, This class keeps track of mementos. In usual cases this would be the client. 79 | ```typescript 80 | class Caretaker { 81 | private mementos: ExhibitMemento[] = []; 82 | 83 | addMemento(memento: ExhibitMemento) { 84 | this.mementos.push(memento); 85 | } 86 | 87 | getMemento(index: number): ExhibitMemento { 88 | return this.mementos[index]; 89 | } 90 | } 91 | ``` 92 | 93 | 5. **Example usage**: This demonstrates how to use the Memento pattern to save and restore the state of the exhibit. 94 | ```typescript 95 | // Example usage 96 | const digitalArtGallery = new Exhibit(); 97 | 98 | // Initial state 99 | digitalArtGallery.setState({ 100 | exhibitName: "Monalisa", 101 | artist: "Leonardo da Vinci", 102 | year: 1503 103 | }); 104 | 105 | const caretaker = new Caretaker(); 106 | 107 | // Save initial state 108 | caretaker.addMemento(digitalArtGallery.saveToMemento()); 109 | 110 | // Make some changes 111 | digitalArtGallery.setState({ 112 | exhibitName: "Starry Night", 113 | artist: "Vincent van Gogh", 114 | year: 1889 115 | }); 116 | 117 | // Save new state 118 | caretaker.addMemento(digitalArtGallery.saveToMemento()); 119 | 120 | // Restore to previous state 121 | digitalArtGallery.restoreFromMemento(caretaker.getMemento(0)); 122 | 123 | console.log(digitalArtGallery.getState()); // Output: { exhibitName: "Monalisa", artist: "Leonardo da Vinci", year: 1503 } 124 | ``` 125 | 126 | **How it works:** 127 | 128 | 1. The Originator class uses the Memento pattern to save and restore its state. 129 | 2. The Memento interface defines the getState() method that returns the state of the object. 130 | 3. The ConcreteMemento class implements the Memento interface and holds the state of the object. 131 | 4. The Originator class uses the ConcreteMemento class to save and restore its state. 132 | 133 | **When to use the Memento pattern over other patterns similar to it:** 134 | 135 | The Memento pattern is particularly useful when you need to capture the internal state of an object in such a way that it can be restored to that state later. While there are other patterns that might seem similar in concept, such as Command each serves a different purpose. Here's when you might choose the Memento pattern over other similar patterns: 136 | 137 | * Memento vs. Command Pattern: 138 | **Command Pattern** is a popular pattern to implement undo, redo functionality, but the command pattern is more about encapsulating a request as an object, allowing for parameterization of clients with queues, requests, and operations. While it can be used for undo functionality, it's focused on encapsulating actions rather than states. **Memento Pattern** although similar captures the internal state of an object without exposing its implementation details. It's mainly concerned with capturing and restoring the state. 139 | 140 | Note that the Memento pattern is often used in combination with other design patterns, such as the Observer pattern, to implement undo/redo functionality. 141 | -------------------------------------------------------------------------------- /BDP-StrategyPattern/code/example-1.ts: -------------------------------------------------------------------------------- 1 | // The strategy interface declares operations common to all 2 | // supported versions of some algorithm. The context uses this 3 | // interface to call the algorithm defined by the concrete 4 | // strategies. 5 | 6 | interface NavigationStrategy { 7 | route(source: string, destination: string): string 8 | } 9 | 10 | // Concrete strategies implement the algorithm while following 11 | // the base strategy interface. The interface makes them 12 | // interchangeable in the context. 13 | 14 | class ByDriving implements NavigationStrategy { 15 | route(source: string, destination: string) { 16 | return `Route from ${source} to ${destination} by driving ...` 17 | } 18 | } 19 | 20 | class ByWalking implements NavigationStrategy { 21 | route(source: string, destination: string) { 22 | return `Route from ${source} to ${destination} by walking ...` 23 | } 24 | } 25 | 26 | class ByPublicTransport implements NavigationStrategy { 27 | route(source: string, destination: string) { 28 | return `Route from ${source} to ${destination} by public transport ...` 29 | } 30 | } 31 | 32 | // The context defines the interface of interest to clients. 33 | class NavigationContext { 34 | // The context maintains a reference to one of the strategy 35 | // objects. The context doesn't know the concrete class of a 36 | // strategy. It should work with all strategies via the 37 | // strategy interface. 38 | private strategy: NavigationStrategy 39 | 40 | constructor(strategy: NavigationStrategy) { 41 | this.strategy = strategy 42 | } 43 | 44 | // Usually the context accepts a strategy through the 45 | // constructor, and also provides a setter so that the 46 | // strategy can be switched at runtime. 47 | setStrategy(strategy: NavigationStrategy) { 48 | this.strategy = strategy 49 | } 50 | 51 | // The context delegates some work to the strategy object 52 | // instead of implementing multiple versions of the 53 | // algorithm on its own. 54 | executeStrategy(source: string, destination: string) { 55 | if (!this.strategy) { return; } 56 | return this.strategy.route(source, destination) 57 | } 58 | } 59 | 60 | // The client code picks a concrete strategy and passes it to 61 | // the context. The client should be aware of the differences 62 | // between strategies in order to make the right choice. 63 | 64 | const source = "Home"; 65 | const destination = "Work"; 66 | enum modeOfTransports { "PUBLIC_TRANSPORT", "WALKING", "DRIVING" }; 67 | const modeOfTransport = modeOfTransports.WALKING; 68 | const defaultStrategy = new ByDriving(); 69 | 70 | const _navigator = new NavigationContext(defaultStrategy); 71 | 72 | switch (+modeOfTransport) { 73 | case modeOfTransports.DRIVING: _navigator.setStrategy(new ByDriving()); 74 | break; 75 | case modeOfTransports.PUBLIC_TRANSPORT: _navigator.setStrategy(new ByPublicTransport()); 76 | break; 77 | case modeOfTransports.WALKING: _navigator.setStrategy(new ByWalking()); 78 | break; 79 | } 80 | 81 | let route = _navigator.executeStrategy(source, destination); 82 | console.log(route); 83 | 84 | _navigator.setStrategy(new ByPublicTransport()) 85 | route = _navigator.executeStrategy(source, destination); 86 | console.log(route); 87 | -------------------------------------------------------------------------------- /BDP-StrategyPattern/code/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "code", 3 | "version": "1.0.0", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "@cspotcode/source-map-consumer": { 8 | "version": "0.8.0", 9 | "resolved": "https://registry.npmjs.org/@cspotcode/source-map-consumer/-/source-map-consumer-0.8.0.tgz", 10 | "integrity": "sha512-41qniHzTU8yAGbCp04ohlmSrZf8bkf/iJsl3V0dRGsQN/5GFfx+LbCSsCpp2gqrqjTVg/K6O8ycoV35JIwAzAg==", 11 | "dev": true 12 | }, 13 | "@cspotcode/source-map-support": { 14 | "version": "0.6.1", 15 | "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.6.1.tgz", 16 | "integrity": "sha512-DX3Z+T5dt1ockmPdobJS/FAsQPW4V4SrWEhD2iYQT2Cb2tQsiMnYxrcUH9By/Z3B+v0S5LMBkQtV/XOBbpLEOg==", 17 | "dev": true, 18 | "requires": { 19 | "@cspotcode/source-map-consumer": "0.8.0" 20 | } 21 | }, 22 | "@tsconfig/node10": { 23 | "version": "1.0.8", 24 | "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.8.tgz", 25 | "integrity": "sha512-6XFfSQmMgq0CFLY1MslA/CPUfhIL919M1rMsa5lP2P097N2Wd1sSX0tx1u4olM16fLNhtHZpRhedZJphNJqmZg==", 26 | "dev": true 27 | }, 28 | "@tsconfig/node12": { 29 | "version": "1.0.9", 30 | "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.9.tgz", 31 | "integrity": "sha512-/yBMcem+fbvhSREH+s14YJi18sp7J9jpuhYByADT2rypfajMZZN4WQ6zBGgBKp53NKmqI36wFYDb3yaMPurITw==", 32 | "dev": true 33 | }, 34 | "@tsconfig/node14": { 35 | "version": "1.0.1", 36 | "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.1.tgz", 37 | "integrity": "sha512-509r2+yARFfHHE7T6Puu2jjkoycftovhXRqW328PDXTVGKihlb1P8Z9mMZH04ebyajfRY7dedfGynlrFHJUQCg==", 38 | "dev": true 39 | }, 40 | "@tsconfig/node16": { 41 | "version": "1.0.2", 42 | "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.2.tgz", 43 | "integrity": "sha512-eZxlbI8GZscaGS7kkc/trHTT5xgrjH3/1n2JDwusC9iahPKWMRvRjJSAN5mCXviuTGQ/lHnhvv8Q1YTpnfz9gA==", 44 | "dev": true 45 | }, 46 | "acorn": { 47 | "version": "8.5.0", 48 | "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.5.0.tgz", 49 | "integrity": "sha512-yXbYeFy+jUuYd3/CDcg2NkIYE991XYX/bje7LmjJigUciaeO1JR4XxXgCIV1/Zc/dRuFEyw1L0pbA+qynJkW5Q==", 50 | "dev": true 51 | }, 52 | "acorn-walk": { 53 | "version": "8.2.0", 54 | "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", 55 | "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", 56 | "dev": true 57 | }, 58 | "arg": { 59 | "version": "4.1.3", 60 | "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", 61 | "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", 62 | "dev": true 63 | }, 64 | "create-require": { 65 | "version": "1.1.1", 66 | "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", 67 | "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", 68 | "dev": true 69 | }, 70 | "diff": { 71 | "version": "4.0.2", 72 | "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", 73 | "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", 74 | "dev": true 75 | }, 76 | "make-error": { 77 | "version": "1.3.6", 78 | "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", 79 | "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", 80 | "dev": true 81 | }, 82 | "ts-node": { 83 | "version": "10.2.1", 84 | "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.2.1.tgz", 85 | "integrity": "sha512-hCnyOyuGmD5wHleOQX6NIjJtYVIO8bPP8F2acWkB4W06wdlkgyvJtubO/I9NkI88hCFECbsEgoLc0VNkYmcSfw==", 86 | "dev": true, 87 | "requires": { 88 | "@cspotcode/source-map-support": "0.6.1", 89 | "@tsconfig/node10": "^1.0.7", 90 | "@tsconfig/node12": "^1.0.7", 91 | "@tsconfig/node14": "^1.0.0", 92 | "@tsconfig/node16": "^1.0.2", 93 | "acorn": "^8.4.1", 94 | "acorn-walk": "^8.1.1", 95 | "arg": "^4.1.0", 96 | "create-require": "^1.1.0", 97 | "diff": "^4.0.1", 98 | "make-error": "^1.1.1", 99 | "yn": "3.1.1" 100 | } 101 | }, 102 | "typescript": { 103 | "version": "4.4.3", 104 | "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.4.3.tgz", 105 | "integrity": "sha512-4xfscpisVgqqDfPaJo5vkd+Qd/ItkoagnHpufr+i2QCHBsNYp+G7UAoyFl8aPtx879u38wPV65rZ8qbGZijalA==", 106 | "dev": true 107 | }, 108 | "yn": { 109 | "version": "3.1.1", 110 | "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", 111 | "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", 112 | "dev": true 113 | } 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /BDP-StrategyPattern/code/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "code", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "keywords": [], 10 | "author": "", 11 | "license": "ISC", 12 | "devDependencies": { 13 | "ts-node": "^10.2.1", 14 | "typescript": "^4.4.3" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /BDP-StrategyPattern/code/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | /* Visit https://aka.ms/tsconfig.json to read more about this file */ 4 | 5 | /* Basic Options */ 6 | // "incremental": true, /* Enable incremental compilation */ 7 | "target": "es5", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', 'ES2021', or 'ESNEXT'. */ 8 | "module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */ 9 | // "lib": [], /* Specify library files to be included in the compilation. */ 10 | // "allowJs": true, /* Allow javascript files to be compiled. */ 11 | // "checkJs": true, /* Report errors in .js files. */ 12 | // "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', 'react', 'react-jsx' or 'react-jsxdev'. */ 13 | // "declaration": true, /* Generates corresponding '.d.ts' file. */ 14 | // "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */ 15 | // "sourceMap": true, /* Generates corresponding '.map' file. */ 16 | // "outFile": "./", /* Concatenate and emit output to single file. */ 17 | // "outDir": "./", /* Redirect output structure to the directory. */ 18 | // "rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */ 19 | // "composite": true, /* Enable project compilation */ 20 | // "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */ 21 | // "removeComments": true, /* Do not emit comments to output. */ 22 | // "noEmit": true, /* Do not emit outputs. */ 23 | // "importHelpers": true, /* Import emit helpers from 'tslib'. */ 24 | // "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */ 25 | // "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */ 26 | 27 | /* Strict Type-Checking Options */ 28 | "strict": true, /* Enable all strict type-checking options. */ 29 | // "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */ 30 | // "strictNullChecks": true, /* Enable strict null checks. */ 31 | // "strictFunctionTypes": true, /* Enable strict checking of function types. */ 32 | // "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */ 33 | // "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */ 34 | // "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */ 35 | // "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */ 36 | 37 | /* Additional Checks */ 38 | // "noUnusedLocals": true, /* Report errors on unused locals. */ 39 | // "noUnusedParameters": true, /* Report errors on unused parameters. */ 40 | // "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */ 41 | // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */ 42 | // "noUncheckedIndexedAccess": true, /* Include 'undefined' in index signature results */ 43 | // "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an 'override' modifier. */ 44 | // "noPropertyAccessFromIndexSignature": true, /* Require undeclared properties from index signatures to use element accesses. */ 45 | 46 | /* Module Resolution Options */ 47 | // "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */ 48 | // "baseUrl": "./", /* Base directory to resolve non-absolute module names. */ 49 | // "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */ 50 | // "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */ 51 | // "typeRoots": [], /* List of folders to include type definitions from. */ 52 | // "types": [], /* Type declaration files to be included in compilation. */ 53 | // "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */ 54 | "esModuleInterop": true, /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */ 55 | // "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */ 56 | // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ 57 | 58 | /* Source Map Options */ 59 | // "sourceRoot": "", /* Specify the location where debugger should locate TypeScript files instead of source locations. */ 60 | // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ 61 | // "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */ 62 | // "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */ 63 | 64 | /* Experimental Options */ 65 | // "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */ 66 | // "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */ 67 | 68 | /* Advanced Options */ 69 | "skipLibCheck": true, /* Skip type checking of declaration files. */ 70 | "forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */ 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /CDP-BuilderPattern/README.md: -------------------------------------------------------------------------------- 1 |

2 |

Builder Pattern

3 |

4 | 5 | > The intent of the Builder Pattern is to facilitate the construction of complex objects by separating the **construction process** from the actual **representation**. By using the Builder Pattern, you can simplify the process of creating complex objects, reduce constructor overloading, and improve the maintainability of your codebase. It's particularly beneficial when dealing with objects that have multiple optional or mandatory parameters and require multiple steps to be properly configured and created. 6 | 7 | ##### In essence, the Builder Pattern provides a structured approach to constructing objects, making your code more organized, flexible, and easier to read. It's a valuable tool in your design pattern toolbox when dealing with complex object creation scenarios. 8 | 9 | *** 10 | 11 | ### The easiest way to understand the intent of the Builder pattern is to look at examples of where it is useful. 12 | 13 | Let's say you wanted to use a method or a subroutine that someone else has written because it performs some function that you need, but you cannot incorporate the routine directly into your program; 14 | 15 | As it maybe a third party software so you cannot make changes to their code and also you don’t want to solve the problem by changing your existing code. 16 | 17 | Or simply the interface or the way of calling the routine is not exactly consistent or equivalent to the way that is related objects need to use it. 18 | The Builder pattern can be a valuable asset in various scenarios within large enterprise applications, where complexity and flexibility are paramount. Here are some areas where the Builder pattern can shine: 19 | 20 | 1. **Object Creation and Initialization**: Large enterprise applications often involve creating complex objects with multiple parameters and optional configurations. The Builder pattern can simplify this process by encapsulating the construction and initialization logic, making the code more readable and maintainable. 21 | 22 | 2. **Configuration Management**: When dealing with intricate system configurations that involve setting up various components with different options, the Builder pattern can help manage and maintain consistent configurations across the application. 23 | 24 | 3. **Database Query Building**: In applications that rely heavily on database interactions, the Builder pattern can be employed to construct dynamic and complex database queries. This ensures the separation of query construction from the database interactions themselves, leading to cleaner and more organized code. 25 | 26 | 4. **UI Component Creation**: Building complex user interfaces often requires assembling various UI components with different attributes and configurations. The Builder pattern can streamline this process by providing a structured way to create and arrange UI components. 27 | 28 | 5. **Document Generation**: In applications that generate reports, documents, or other formatted outputs, the Builder pattern can assist in creating and formatting these documents. It abstracts away the complexities of formatting while allowing for customization. 29 | 30 | 6. **Data Transformation**: Large enterprise applications often involve data transformation and mapping between different formats or structures. The Builder pattern can aid in constructing transformation pipelines, ensuring data consistency and facilitating the conversion process. 31 | 32 | 7. **Communication and Integration**: When integrating with external systems, services, or APIs, the Builder pattern can help standardize communication protocols and message formats, making it easier to manage interactions and adapt to changes. 33 | 34 | 8. **Test Data Generation**: For testing purposes, generating realistic and diverse test data can be challenging. The Builder pattern can be used to create builder objects specifically designed to generate valid and varied test data. 35 | 36 | 9. **Workflow and Process Orchestration**: When orchestrating complex workflows or processes, the Builder pattern can be applied to build sequences of actions or tasks while allowing for dynamic adjustments and customizations. 37 | 38 | 10. **Plugin and Extension Systems**: Large applications often support plugins or extensions. The Builder pattern can help define a consistent interface for plugin construction and initialization, ensuring that plugins are integrated seamlessly into the application. 39 | 40 | In summary, the Builder pattern's ability to encapsulate construction and configuration processes, manage complexity, and promote flexibility makes it a powerful tool in designing large enterprise applications that require modular, maintainable, and extensible codebases. 41 | 42 | *** 43 | 44 | ### Steps to implementing the adapter pattern. 45 | 46 | > **AGENDA** : The Adapter pattern allows otherwise incompatible classes to work together by converting the interface of one class into an interface expected by the clients. 47 | 48 | 1. First we **Identify the complex object(s)** you want to create. Define its attributes, properties, and possible configurations. This is the object that the builder will construct. 49 | ```TS 50 | // Step 1: Define the Product 51 | class Car { 52 | constructor(public make: string, public model: string, public year: number) {} 53 | } 54 | ``` 55 | 56 | 2. Then **identify the Builder Interface**, Design an abstract interface or class that defines the methods for constructing and configuring the parts of the complex object. These methods should cover various aspects of object creation. 57 | ```TS 58 | // Step 2: Create the Builder Interface 59 | interface CarBuilder { 60 | setMake(make: string): void; 61 | setModel(model: string): void; 62 | setYear(year: number): void; 63 | build(): Car; 64 | } 65 | ``` 66 | 67 | 3. **Create one or more concrete classes** that implement the builder interface. Each concrete builder should provide methods to build different parts of the complex object and assemble them. 68 | ```TS 69 | // Step 3: Implement Concrete Builders 70 | class SedanBuilder implements CarBuilder { 71 | private car: Car; 72 | 73 | constructor() { 74 | this.car = new Car("Unknown", "Unknown", 0); 75 | } 76 | 77 | setMake(make: string): void { 78 | this.car.make = make; 79 | } 80 | 81 | setModel(model: string): void { 82 | this.car.model = model; 83 | } 84 | 85 | setYear(year: number): void { 86 | this.car.year = year; 87 | } 88 | 89 | build(): Car { 90 | return this.car; 91 | } 92 | } 93 | ``` 94 | 95 | 4. Create the Director (Optional): Consider implementing a director class that coordinates the construction process using a builder. The director can provide a higher-level interface for building objects and managing the order of construction steps. 96 | 97 | 5. Client Code: In the client code, create an instance of the builder you want to use. Use the builder's methods to set the attributes and configurations of the complex object. 98 | ```TS 99 | // Step 5: Client Code 100 | const sedanBuilder = new SedanBuilder(); 101 | sedanBuilder.setMake("Toyota"); 102 | sedanBuilder.setModel("Camry"); 103 | sedanBuilder.setYear(2022); 104 | ``` 105 | 106 | 6. Build the Object: Call the builder's methods to construct the complex object step by step. The builder handles the construction details, ensuring that the final object is properly initialized. 107 | ```TS 108 | // Step 6: Build the Object 109 | const car: Car = sedanBuilder.build(); 110 | ``` 111 | 112 | 7. Obtain the Result: After constructing the object, use a method provided by the builder to obtain the final product. This method should return the fully constructed and configured complex object. 113 | ```TS 114 | // Step 7: Obtain the Result 115 | console.log(car); 116 | ``` 117 | 118 | > Use the Complex Object: Once you have the constructed complex object, you can use it as needed within your application. 119 | 120 | *** 121 | 122 |

When to use Builder pattern over other patterns

123 | 124 | The decision to use the Builder pattern over other patterns depends on the specific requirements and constraints of your project. While the Builder pattern is valuable in certain scenarios, there are situations where it may be a better choice compared to other patterns: 125 | 126 | 1. **Builder vs. Telescoping Constructors (Anti-Pattern)**: 127 | - Use Builder when you have a class with multiple optional parameters or configurations that can lead to confusing and error-prone telescoping constructors. 128 | - Telescoping constructors become unwieldy as the number of parameters increases, whereas the Builder pattern provides a more structured and readable way to initialize objects. 129 | 130 | 2. **Builder vs. Factory Method**: 131 | - Use Builder when you need to create complex objects with multiple configurable attributes or parts. 132 | - Factory Method is more suitable when you want to delegate the responsibility of object creation to subclasses, providing a way to create different types of related objects. 133 | 134 | 3. **Builder vs. Prototype**: 135 | - Use Builder when you want to construct complex objects step by step, specifying different attributes and configurations during the construction process. 136 | - Prototype is more suitable when you need to create copies of existing objects efficiently, especially when the creation process is resource-intensive. 137 | 138 | 4. **Builder vs. Abstract Factory**: 139 | - Use Builder when you need to create complex objects with a specific configuration. 140 | - Abstract Factory is more suitable when you want to provide an interface for creating families of related or dependent objects, adhering to a common theme. 141 | 142 | 5. **Builder vs. Singleton**: 143 | - Use Builder when you want to construct multiple instances of a complex object with various configurations. 144 | - Singleton is used to ensure that a class has only one instance and provides a global point of access to that instance. 145 | 146 | 6. **Builder vs. Decorator**: 147 | - Use Builder when you want to construct a complete object with various attributes and configurations. 148 | - Decorator is more suitable when you want to dynamically add responsibilities or behaviors to objects without altering their structure. 149 | 150 | In summary, use the Builder pattern when you need to create complex objects step by step, with multiple configurable attributes or parts. The Builder pattern excels in scenarios where the construction process involves a combination of parameters, optional settings, and a clear separation between object construction and representation. While other design patterns also address object creation and initialization, the Builder pattern's focus on gradual and controlled construction makes it a valuable choice in specific situations. 151 | 152 | -------------------------------------------------------------------------------- /CDP-PrototypePattern/README.md: -------------------------------------------------------------------------------- 1 |

2 |

Prototype Pattern

3 |

4 | 5 | > The Prototype pattern is a creational design pattern that focuses on creating new objects by copying or cloning existing instances, known as prototypes. It allows you to create new objects that are initially similar to existing ones, making use of a prototype object as a template. This pattern is particularly useful when creating objects is costly in terms of resources or time, and you want to avoid the overhead of repeatedly creating objects from scratch. 6 | 7 | *** 8 | 9 | ### The easiest way to understand the intent of the Prototype pattern is to look at examples of where it is useful. 10 | 11 | Let's say you are developing a game and need to create various instances of a character class with different attributes and abilities. Instead of creating each character from scratch, you can use the Prototype pattern. You create a prototype instance of the character class and then clone it to create new characters with similar attributes. This approach not only saves resources but also ensures consistency among character instances. 12 | 13 | *** 14 | 15 | ### Steps to implementing the adapter pattern. 16 | 17 | > **AGENDA** : The Adapter pattern allows otherwise incompatible classes to work together by converting the interface of one class into an interface expected by the clients. 18 | 19 | 1. Prototype: The prototype is an existing object that serves as a blueprint for creating new instances. It defines an interface for cloning itself. 20 | ```TS 21 | interface Prototype { 22 | clone(): Prototype; 23 | } 24 | ``` 25 | 26 | 2. Concrete Prototype: Concrete prototypes are specific instances of the prototype object. They implement the cloning interface and provide a method to create a copy of themselves. 27 | ```TS 28 | // Concrete prototype class 29 | class Character implements Prototype { 30 | constructor(public name: string, public type: string) {} 31 | 32 | clone(): Prototype { 33 | return new Character(this.name, this.type); 34 | } 35 | } 36 | ``` 37 | 38 | 3. Client: The client is responsible for creating new objects by requesting clones of existing prototypes. It interacts with the prototype's cloning mechanism. 39 | ```TS 40 | // Client code 41 | const originalCharacter = new Character("Warrior", "Knight"); 42 | const clonedCharacter = originalCharacter.clone(); 43 | 44 | console.log(originalCharacter); // Output: Character { name: 'Warrior', type: 'Knight' } 45 | console.log(clonedCharacter); // Output: Character { name: 'Warrior', type: 'Knight' } 46 | ``` 47 | 48 | 49 | *** 50 | 51 |

When to use Builder pattern over other patterns

52 | 53 | The decision to use the Builder pattern over other patterns depends on the specific requirements and constraints of your project. While the Builder pattern is valuable in certain scenarios, there are situations where it may be a better choice compared to other patterns: 54 | 55 | 1. **Builder vs. Telescoping Constructors (Anti-Pattern)**: 56 | - Use Builder when you have a class with multiple optional parameters or configurations that can lead to confusing and error-prone telescoping constructors. 57 | - Telescoping constructors become unwieldy as the number of parameters increases, whereas the Builder pattern provides a more structured and readable way to initialize objects. 58 | 59 | 2. **Builder vs. Factory Method**: 60 | - Use Builder when you need to create complex objects with multiple configurable attributes or parts. 61 | - Factory Method is more suitable when you want to delegate the responsibility of object creation to subclasses, providing a way to create different types of related objects. 62 | 63 | 3. **Builder vs. Prototype**: 64 | - Use Builder when you want to construct complex objects step by step, specifying different attributes and configurations during the construction process. 65 | - Prototype is more suitable when you need to create copies of existing objects efficiently, especially when the creation process is resource-intensive. 66 | 67 | 4. **Builder vs. Abstract Factory**: 68 | - Use Builder when you need to create complex objects with a specific configuration. 69 | - Abstract Factory is more suitable when you want to provide an interface for creating families of related or dependent objects, adhering to a common theme. 70 | 71 | 5. **Builder vs. Singleton**: 72 | - Use Builder when you want to construct multiple instances of a complex object with various configurations. 73 | - Singleton is used to ensure that a class has only one instance and provides a global point of access to that instance. 74 | 75 | 6. **Builder vs. Decorator**: 76 | - Use Builder when you want to construct a complete object with various attributes and configurations. 77 | - Decorator is more suitable when you want to dynamically add responsibilities or behaviors to objects without altering their structure. 78 | 79 | In summary, use the Builder pattern when you need to create complex objects step by step, with multiple configurable attributes or parts. The Builder pattern excels in scenarios where the construction process involves a combination of parameters, optional settings, and a clear separation between object construction and representation. While other design patterns also address object creation and initialization, the Builder pattern's focus on gradual and controlled construction makes it a valuable choice in specific situations. 80 | 81 | -------------------------------------------------------------------------------- /Object-Oriented-Programming/UML-CheetSheet.md: -------------------------------------------------------------------------------- 1 |

2 |

Unified Modeling Language

3 | 4 |

5 | 6 | > UML, short for Unified Modeling Language, is a visual language filled with drawing notation and semantics used to create models of programs. UML is used to express the design of software Designs, patterns and architecture. 7 | 8 | *** 9 | 10 | ## Why to Learn UML 11 | 12 | * The UML is not only a better way of describing object-oriented designs. It also forces the designer to think through the relationships between classes in their approach as it needs to be written. 13 | 14 | * Complex applications need collaboration and planning from multiple teams and hence require a clear and concise way to communicate among them. 15 | 16 | *** 17 | 18 | ## Unified Modelling language - Basics 19 | 20 | ### :arrow_right: Abstract Class 21 | 22 | 23 | 24 | > Abstract class is a class which may have some unimplemented methods. These methods are called abstract methods. We can't create an instance of an abstract class. But other classes can be derived from abstract class and reuse the functionality of base class.
25 | * Abstract keyword before the method name. 26 | * Abstract method does not have any implementation. 27 | 28 | 29 | ### :arrow_right: Class Diagram 30 | 31 |
A class is depicted as a rectangle with the class name in bold. Any data that the class defines comes after the class name. Operations appear in normal type below the class attributes. Lines separate the class name from the operations and the operations from the data.
32 | 33 | *** 34 | 35 | ### :arrow_right: Class Attributes Visibility 36 | 37 |
Describes the accessibility of an attribute of a class,these notations must be placed before the member's name.
38 | 39 | | `Access Right` |`public (+)`|`private (-)`| `protected (#)`| `Package (~)` | 40 | | :-------------------------- |:---------: | :-----------: | :-----------: | :-----------: | 41 | | `Members of the same class` | `yes` |`yes` | `yes` | `yes` | 42 | | `Members of derived classes`| `yes` |`no` | `yes` | `yes` | 43 | | `Members of any other class`| `yes` |`no` | `no` | `in same package` | 44 | 45 | *** 46 | 47 | ### :arrow_right: Aggregation 48 | 49 |
There are actually two different kinds of has-a relationships. One object can have another object where the contained object is a part of the containing object — or not.
50 | For example a 'Car Showroom' "has" Cars. Cars are not part of 'Car Showroom', but I can still say that a 'Car Showroom' has them. This type of relationship is called aggregation. 51 | 52 |
53 | 54 | 55 | *** 56 | 57 | 58 | ### :arrow_right: Composition 59 | 60 |
The other type of has-a relationship is where the containment means the contained object is a part of the containing object. This type of relationship is also called composition.
61 | A Car has Tires as parts (that is, the Car is made up of Tires and other things). This type of has-a relationship, called composition, is depicted by the filled in diamond.
62 | Both composition and aggregation involve one object containing one or more objects. Composition, however, implies the contained object is a part of the containing object, whereas aggregation means the contained objects are more like a collection of things. 63 |
64 | 65 | *** 66 | 67 | 68 | ### :arrow_right: Dependency 69 | 70 | 71 | 72 |
73 | Dependency is a weaker form of bond that indicates that one class depends on another because it uses it at some point in time. One class depends on another if the independent class is a parameter variable or local variable of a method of the dependent class.
74 | For example, This diagram shows that a Car uses a 'GasStation'. The uses relationship is depicted by a dashed line with an arrow. This is also called a dependency relationship. 75 |
76 | 77 | *** 78 |

79 | ### :arrow_right: Inheritance 80 | 81 | 82 | 83 |
Inheritance is a mechanism by which child classes inherit the properties of their parent classes. The easiest way to understand Inheritance is to think of it as a is-a relationship.
84 | for example, Sedan is-a a type of car, Hatchback is-a a type of car just like SUV is-a a type of car
85 | 86 | *** 87 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 |

Design Patterns in TypeScript

3 | 4 |

5 | 6 |

7 | Creational Design Patterns | 8 | Structural Design Patterns | 9 | Behavioral Design Patterns 10 |

11 | 12 |

13 | 14 | Discord Chat 15 | 16 | 17 | Discord Server 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 |

26 | 27 | 28 | > In software engineering, a software design pattern is a general reusable solution to a commonly occurring problem within a given context in software design. It is not a finished design that can be transformed directly into source or machine code. It is a description or template for how to solve a problem that can be used in many different situations. 29 | 30 | ___ 31 | 32 |
33 | This article assumes you are reasonably proficient in at least one object-oriented programming language, and you should have some experience in object-oriented design as well. You definitely shouldn't have to rush to the nearest dictionary the moment we mention "types" and "polymorphism," or "interface" as opposed to "implementation / inheritance”. 34 |
But I'll try to keep the literature as simple as possible. 35 |

Don't worry if you don’t understand this article completely on the first reading. We didn’t understand it all on the first writing! Remember that this isn't an article to read once and forget it. We hope you'll find yourself referring to it again and again for design insights and for inspiration. 36 |
37 | 38 | ___ 39 | 40 |

41 |

Object-Oriented Terminology

42 |

43 | 44 | |

Term

|
Definition
| 45 | | :------------: | :--------------------------------------------------------------------------- | 46 | |

Abstract class

|
Defines the methods and common attributes of a set of classes that are conceptually similar. Abstract classes are never instantiated.
| 47 | |

Attribute

|
Data associated with an object (also called a data member).
| 48 | |

Class

|
Blueprint of an object—defines the methods and data of an object of its type.
| 49 | |

Constructor

|
Special method that is invoked when an object is created.
| 50 | |

Encapsulation

|
Any kind of hiding. Objects encapsulate their data. Abstract classes encapsulate their derived concrete classes.
| 51 | |

Derived class

|
A class that is specialized from a superclass. Contains all of the attributes and methods of the superclass but may also contain other attributes or dif-ferent method implementations.
| 52 | |

Destructor

|
Special method that is invoked when an object is deleted.
| 53 | |

Functional decomposition

|
A method of analysis in which a problem is broken into smaller and smaller functions.
| 54 | |

Inheritance

|
The way that a class is specialized, used to relate derived classes from their abstractions.
| 55 | |

Instance

|
A particular object of a class.
| 56 | |

Instantiation

|
The process of creating an instance of a class.MemberEither data or method of a class.
| 57 | |

Method

|
Functions that are associated with an object.
| 58 | |

Object

|
An entity with responsibilities. A special, self-contained holder of both data and methods that operate on that data. An object’s data are protected from external objects.
| 59 | |

Polymorphism

|
The ability of related objects to implement methods that are specialized to their type.
| 60 | |

Superclass

|
A class from which other classes are derived. Contains the master definitions of attributes and methods that all derived classes will use (and possibly will override).
| 61 | 62 | ___ 63 | 64 |

65 |

Creational Design Patterns

66 |

67 | 68 | 69 | 70 | > Creational Design Patterns are concerned with the way in which objects are created. 71 | 72 |
73 | Creational design patterns abstract the instantiation process, meaning construction of objects is decoupled from their implementation logic.
74 | They help make a system independent of how its objects are created,composed, and represented.
75 | Encapsulate knowledge about which concreate classes the system uses.
76 | Hide how instances of these classes are created and put together.

77 | Note : A class creational pattern uses inheritance to vary the class that's instantiated, where as an object creational pattern will delegate instantiation to another object. 78 |
79 | 80 |
81 | Creational Design patterns Table 82 |
83 | 84 | | Thumbnail | Design Pattern | 85 | | :-------------: | :------------------------------------------------------------------------------- | 86 | | Udacity| [Factory Method](https://classroom.udacity.com/courses/ud187)
The factory pattern takes out the responsibility of instantiating a object from the class to a Factory class.
Creates an instance of several derived classes.
| 87 | | Udacity| [Abstract Factory](https://classroom.udacity.com/courses/ud187)
Allows us to create a Factory for factory classes.
The abstract factory pattern provides a way to encapsulate a group of individual factories that have a common theme without specifying their concrete classes.
| 88 | | Udacity| [Builder](https://classroom.udacity.com/courses/ud187)
Creating an object step by step and a method to finally get the object instance.
Allows you to create different flavors of an object while avoiding constructor pollution. Useful when there could be several flavors of an object. Or when there are a lot of steps involved in creation of an object.
| 89 | | Udacity| [Prototype](https://classroom.udacity.com/courses/ud187)
Create object based on an existing object through cloning.
Creating a new object instance from another similar instance and then modify according to our requirements.
| 90 | | Udacity| [Singleton](https://classroom.udacity.com/courses/ud187)
In Ensures a class has only one instance and provide a global point of access to it.
Singleton pattern is a software design pattern that restricts the instantiation of a class to one object. This is useful when exactly one object is needed to coordinate actions across the system.
| 91 | | Udacity| [Object Pool Design Pattern](https://classroom.udacity.com/courses/ud187)
Object pools are used to manage the object caching.
Avoid expensive acquisition and release of resources by recycling objects that are no longer in use.
| 92 | 93 |
94 | 95 | *** 96 | 97 |

98 |

99 |

Structural design patterns

100 |

101 | 102 | 103 | 104 | > Structural patterns are mostly concerned with object composition or in other words how the entities can use each other. Or yet another explanation would be, they help in answering "How to build a software component?" 105 | 106 |
107 | Structural patterns explain how to assemble objects and classes into larger structures while keeping these structures flexible and efficient.
108 | A structural design pattern serves as a blueprint for how different classes and objects are combined to form larger structures. Unlike creational patterns, which are mostly different ways to fulfill the same fundamental purpose, each structural pattern has a different purpose. 109 |
110 |
111 | 112 |
113 | Structural Design patterns Table 114 |
115 | 116 | | Thumbnail | Design Pattern | 117 | | :-------------: | :------------------------------------------------------------------------------- | 118 | | Udacity| [Adapter](https://classroom.udacity.com/courses/ud187)
Provides an interface between two unrelated entities so that they can work together.
| 119 | | Udacity| [Composite](https://classroom.udacity.com/courses/ud187)
Used when we have to implement a part-whole hierarchy. For example, a diagram made of other pieces such as circle, square, triangle, etc.
| 120 | | Udacity| [Proxy](https://classroom.udacity.com/courses/ud187)
Provide a surrogate or placeholder for another object to control access to it.
| 121 | | Udacity| [Flyweight](https://classroom.udacity.com/courses/ud187)
Caching and reusing object instances, used with immutable objects. For example, string pool.
| 122 | | Udacity| [Facade](https://classroom.udacity.com/courses/ud187)
Creating a wrapper interfaces on top of existing interfaces to help client applications.
| 123 | | Udacity| [Bridge](https://classroom.udacity.com/courses/ud187)
The bridge design pattern is used to decouple the interfaces from implementation and hiding the implementation details from the client program.
| 124 | | Udacity| [Decorator](https://classroom.udacity.com/courses/ud187)
The decorator design pattern is used to modify the functionality of an object at runtime.
| 125 | 126 |
127 | 128 | ___ 129 | 130 |

131 |

132 |

Behavioral Design Patterns

133 |

134 | 135 | 136 | 137 | > Behavioral design patterns are concerned with algorithms and the assignment of responsibilities between objects. 138 | 139 |
140 | Behavioral Design Patterns identify common communication patterns between objects and realize these patterns. By doing so, these patterns increase flexibility in carrying out this communication.
141 | What makes them different from structural patterns is they don't just specify the structure but also outline the patterns for message passing/communication between them. Or in other words, they assist in answering "How to run a behavior in software component?"
142 |
143 | 144 |
145 | Behavioral Design patterns Table 146 |
147 | 148 | | Thumbnail | Design Pattern | 149 | | :-------------: | :------------------------------------------------------------------------------- | 150 | | Udacity| [Template Method](https://classroom.udacity.com/courses/ud187)
used to create a template method stub and defer some of the steps of implementation to the subclasses.
| 151 | | Udacity| [Mediator](https://classroom.udacity.com/courses/ud187)
used to provide a centralized communication medium between different objects in a system.
| 152 | | Udacity| [Chain of Responsibility](https://classroom.udacity.com/courses/ud187)
used to achieve loose coupling in software design where a request from the client is passed to a chain of objects to process them.
| 153 | | Udacity| [Observer](https://classroom.udacity.com/courses/ud187)
useful when you are interested in the state of an object and want to get notified whenever there is any change.
| 154 | | Udacity| [Strategy](https://classroom.udacity.com/courses/ud187)
Strategy pattern is used when we have multiple algorithm for a specific task and client decides the actual implementation to be used at runtime.
| 155 | | Udacity| [Command](https://classroom.udacity.com/courses/ud187)
Command Pattern is used to implement lose coupling in a request-response model.
| 156 | | Udacity| [State](https://classroom.udacity.com/courses/ud187)
State design pattern is used when an Object change it’s behavior based on it’s internal state.
| 157 | | Udacity| [Visitor](https://classroom.udacity.com/courses/ud187)
Visitor pattern is used when we have to perform an operation on a group of similar kind of Objects.
| 158 | | Udacity| [Interpreter](https://classroom.udacity.com/courses/ud187)
defines a grammatical representation for a language and provides an interpreter to deal with this grammar.
| 159 | | Udacity| [Iterator](https://classroom.udacity.com/courses/ud187)
used to provide a standard way to traverse through a group of Objects.
| 160 | | Udacity| [Memento](https://classroom.udacity.com/courses/ud187)
The memento design pattern is used when we want to save the state of an object so that we can restore later on.
| 161 | 162 |
163 | 164 | ___ 165 | 166 |

167 | ### Conclusion 168 | 169 | > Once you understand the design patterns and have had an "**Aha!**" (and not just a "Huh?") experience with them, you won't ever think about object-oriented design in the same way. 170 | 171 | The intent of this Article is provide you with insights that can make your own designs more flexible, modular, reusable, and understandable. 172 | ___ 173 | 174 | ### Credits 175 | 176 | > Inspiration -> [Ahmed Kamran](https://twitter.com/kamranahmedse) 177 | -------------------------------------------------------------------------------- /SDP-AdapterPattern/README.md: -------------------------------------------------------------------------------- 1 |

2 |

Adapter Pattern

3 | 4 |

5 | 6 | > The intent of the Design Pattern is to convert the **interface** of a class into another **interface** that the **clients** expect. Adapter lets classes work together that could not otherwise because of **incompatible** interfaces. 7 | 8 | ##### So in simple terms the Adapter Pattern is used to Wrap an existing class with a new interface, it works as a bridge between two incompatible interfaces. This pattern involves a single class called adapter which is responsible for communication between two independent or incompatible interfaces. 9 | 10 | *** 11 | 12 | ### The easiest way to understand the intent of the Adapter pattern is to look at examples of where it is useful. 13 | 14 | Let's say you wanted to use a method or a subroutine that someone else has written because it performs some function that you need, but you cannot incorporate the routine directly into your program; 15 | 16 | As it maybe a third party software so you cannot make changes to their code and also you don’t want to solve the problem by changing your existing code. 17 | 18 | Or simply the interface or the way of calling the routine is not exactly consistent or equivalent to the way that is related objects need to use it. 19 | 20 | *** 21 | 22 | ### Steps to implementing the adapter pattern. 23 | 24 | > **AGENDA** : The Adapter pattern allows otherwise incompatible classes to work together by converting the interface of one class into an interface expected by the clients. 25 | 26 | 1. First we **identify the component(s)** that want to be accommodated (i.e. **the client**), and the component that needs to adapt (i.e. **the adaptee**). 27 | 28 | 2. Then **identify the interface** that the client requires. 29 | 30 | 3. **Design a adapter/wrapper class** that can match the adaptee functions to the client's requirements. 31 | 32 | 4. The **adapter/wrapper** class "**has a**" instance of the **adaptee class**. 33 | 34 | 5. The **adapter/wrapper** class "**maps**" the client interface to the **adaptee interface**. 35 | 36 | 6. The client uses the **new** interface. 37 | 38 | *** 39 | 40 | ### Types of Adapter Pattern 41 | 42 | There are actually two types of Adapter patterns: 43 | 44 | 1. **Object Adapter pattern** : 45 | * The **composition** approach or the "**has a**" approach to implementing the adapter pattern. 46 | * In this approach the adapter/wrapper class relies on one **object** of the **adaptee class**. 47 | * So when a **adapter/wrapper class** object is **instantiated**, it must **instantiate a corresponding** **adaptee class** object. Anything the adapter/wrapper object is told to do will get **passed** to the **adaptee class** object. 48 | 49 | 2. **Class Adapter pattern** : 50 | * The **inheritance** approach or the "**is a**" approach to implementing the adapter pattern. 51 | * In this approach we create a new class which **derives publicly** *from* our **abstract class** to define it's interface and **derives privately** *from* our **existing class** to access it's implementation. 52 | * So in simpler terms **unlike** the **Object Adapter pattern** which creates an object of the adaptee class and simply passes any function invocation to the adaptee class object, the **Class Adapter pattern** since it **extends/derives** from the adaptee class it is able to call the methods of the adaptee class from within it's new interface. (basically call adaptee class methods from it's own custom methods without an object.) 53 | 54 | *** 55 | 56 |

When to use Adapter pattern over other patterns

57 | 58 |
59 | When there's preexisting classes. (client and adaptee class)
60 | When there's a client class-interface the adapter must be designed to. 61 |
62 | 63 |
To keep this article very simple and concise I'll try not to overload the article with other patterns.But at a very high level the Facade and the Adapter pattern seem similar. As they both have preexisting classes and at a high level we do create a wrapper class.
64 | But ultimately what you should keep in mind A Facade simplifies an interface while an Adapter converts a preexisting interface into another interface.
65 | More about Facade pattern in the next articles.
66 | 67 | *** 68 | -------------------------------------------------------------------------------- /SDP-DecoratorPattern/code/example-1.ts: -------------------------------------------------------------------------------- 1 | abstract class AbstractTicket { 2 | abstract printTicket(): void; 3 | } 4 | 5 | class Ticket extends AbstractTicket { 6 | printTicket() { 7 | console.log(` 8 | =========================================================== 9 | || || 10 | || Ticket || 11 | || || 12 | =========================================================== 13 | `) 14 | } 15 | } 16 | 17 | abstract class TicketDecorator extends AbstractTicket { 18 | private ticket: AbstractTicket; 19 | constructor(ticket: AbstractTicket) { 20 | super(); 21 | this.ticket = ticket; 22 | } 23 | public decorateTicket() { 24 | if(this.ticket !== null) { 25 | this.ticket.printTicket(); 26 | } 27 | } 28 | } 29 | 30 | class Header extends TicketDecorator { 31 | constructor(ticket: AbstractTicket) { 32 | super(ticket); 33 | } 34 | printTicket() { 35 | console.log(` 36 | =========================================================== 37 | || Header || 38 | =========================================================== 39 | `) 40 | super.decorateTicket(); 41 | } 42 | } 43 | 44 | class Title extends TicketDecorator { 45 | constructor(ticket: AbstractTicket) { 46 | super(ticket); 47 | } 48 | printTicket() { 49 | console.log(` 50 | =========================================================== 51 | || Title || 52 | =========================================================== 53 | `) 54 | super.decorateTicket(); 55 | } 56 | } 57 | 58 | class Footer extends TicketDecorator { 59 | constructor(ticket: AbstractTicket) { 60 | super(ticket); 61 | } 62 | printTicket() { 63 | super.decorateTicket(); 64 | console.log(` 65 | =========================================================== 66 | || Footer || 67 | =========================================================== 68 | `) 69 | } 70 | } 71 | 72 | let ticket = new Ticket(); 73 | ticket = new Header(ticket); 74 | ticket = new Title(ticket); 75 | ticket = new Footer(ticket); 76 | ticket.printTicket(); -------------------------------------------------------------------------------- /SDP-DecoratorPattern/code/example-2.ts: -------------------------------------------------------------------------------- 1 | // The interface Coffee defines the functionality of Coffee implemented by decorator 2 | abstract class Coffee { 3 | public abstract getCost(): number; // Returns the cost of the coffee 4 | public abstract getIngredients(): string; // Returns the ingredients of the coffee 5 | } 6 | 7 | // Extension of a simple coffee without any extra ingredients 8 | class SimpleCoffee extends Coffee { 9 | public getCost() { 10 | return 1; 11 | } 12 | public getIngredients() { 13 | return "Coffee"; 14 | } 15 | } 16 | 17 | // Abstract decorator class - note that it implements Coffee interface 18 | abstract class CoffeeDecorator extends Coffee { 19 | private decoratedCoffee: Coffee; 20 | 21 | public constructor(coffee: Coffee) { 22 | super() 23 | this.decoratedCoffee = coffee; 24 | } 25 | 26 | public getCost() { // Implementing methods of the interface 27 | return this.decoratedCoffee.getCost(); 28 | } 29 | 30 | public getIngredients() { 31 | return this.decoratedCoffee.getIngredients(); 32 | } 33 | } 34 | 35 | // Decorator WithMilk mixes milk into coffee. 36 | // Note it extends CoffeeDecorator. 37 | class WithMilk extends CoffeeDecorator { 38 | public constructor(coffee: Coffee) { 39 | super(coffee); 40 | } 41 | 42 | public getCost() { // Overriding methods defined in the abstract superclass 43 | return super.getCost() + 0.5; 44 | } 45 | 46 | public getIngredients() { 47 | return super.getIngredients() + ", Milk"; 48 | } 49 | } 50 | 51 | // Decorator WithSprinkles mixes sprinkles onto coffee. 52 | // Note it extends CoffeeDecorator. 53 | class WithSprinkles extends CoffeeDecorator { 54 | public constructor(coffee: Coffee) { 55 | super(coffee); 56 | } 57 | 58 | public getCost() { 59 | return super.getCost() + 0.2; 60 | } 61 | 62 | public getIngredients() { 63 | return super.getIngredients() + ", Sprinkles"; 64 | } 65 | } 66 | 67 | class WithMatcha extends CoffeeDecorator { 68 | constructor(coffee: Coffee) { 69 | super(coffee); 70 | } 71 | 72 | public getCost() { 73 | return super.getCost() + 2; 74 | } 75 | 76 | public getIngredients() { 77 | return super.getIngredients() + ", Matcha"; 78 | } 79 | } 80 | 81 | let coffee = new SimpleCoffee(); 82 | console.log(`${coffee.getIngredients()} :: ${coffee.getCost()}`); 83 | 84 | coffee = new WithMilk(coffee); 85 | console.log(`${coffee.getIngredients()} :: ${coffee.getCost()}`); 86 | 87 | coffee = new WithMatcha(coffee); 88 | coffee = new WithSprinkles(coffee); 89 | console.log(`${coffee.getIngredients()} :: ${coffee.getCost()}`); -------------------------------------------------------------------------------- /SDP-DecoratorPattern/code/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "code", 3 | "version": "1.0.0", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "@cspotcode/source-map-consumer": { 8 | "version": "0.8.0", 9 | "resolved": "https://registry.npmjs.org/@cspotcode/source-map-consumer/-/source-map-consumer-0.8.0.tgz", 10 | "integrity": "sha512-41qniHzTU8yAGbCp04ohlmSrZf8bkf/iJsl3V0dRGsQN/5GFfx+LbCSsCpp2gqrqjTVg/K6O8ycoV35JIwAzAg==", 11 | "dev": true 12 | }, 13 | "@cspotcode/source-map-support": { 14 | "version": "0.6.1", 15 | "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.6.1.tgz", 16 | "integrity": "sha512-DX3Z+T5dt1ockmPdobJS/FAsQPW4V4SrWEhD2iYQT2Cb2tQsiMnYxrcUH9By/Z3B+v0S5LMBkQtV/XOBbpLEOg==", 17 | "dev": true, 18 | "requires": { 19 | "@cspotcode/source-map-consumer": "0.8.0" 20 | } 21 | }, 22 | "@tsconfig/node10": { 23 | "version": "1.0.8", 24 | "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.8.tgz", 25 | "integrity": "sha512-6XFfSQmMgq0CFLY1MslA/CPUfhIL919M1rMsa5lP2P097N2Wd1sSX0tx1u4olM16fLNhtHZpRhedZJphNJqmZg==", 26 | "dev": true 27 | }, 28 | "@tsconfig/node12": { 29 | "version": "1.0.9", 30 | "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.9.tgz", 31 | "integrity": "sha512-/yBMcem+fbvhSREH+s14YJi18sp7J9jpuhYByADT2rypfajMZZN4WQ6zBGgBKp53NKmqI36wFYDb3yaMPurITw==", 32 | "dev": true 33 | }, 34 | "@tsconfig/node14": { 35 | "version": "1.0.1", 36 | "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.1.tgz", 37 | "integrity": "sha512-509r2+yARFfHHE7T6Puu2jjkoycftovhXRqW328PDXTVGKihlb1P8Z9mMZH04ebyajfRY7dedfGynlrFHJUQCg==", 38 | "dev": true 39 | }, 40 | "@tsconfig/node16": { 41 | "version": "1.0.2", 42 | "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.2.tgz", 43 | "integrity": "sha512-eZxlbI8GZscaGS7kkc/trHTT5xgrjH3/1n2JDwusC9iahPKWMRvRjJSAN5mCXviuTGQ/lHnhvv8Q1YTpnfz9gA==", 44 | "dev": true 45 | }, 46 | "acorn": { 47 | "version": "8.5.0", 48 | "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.5.0.tgz", 49 | "integrity": "sha512-yXbYeFy+jUuYd3/CDcg2NkIYE991XYX/bje7LmjJigUciaeO1JR4XxXgCIV1/Zc/dRuFEyw1L0pbA+qynJkW5Q==", 50 | "dev": true 51 | }, 52 | "acorn-walk": { 53 | "version": "8.2.0", 54 | "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", 55 | "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", 56 | "dev": true 57 | }, 58 | "arg": { 59 | "version": "4.1.3", 60 | "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", 61 | "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", 62 | "dev": true 63 | }, 64 | "create-require": { 65 | "version": "1.1.1", 66 | "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", 67 | "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", 68 | "dev": true 69 | }, 70 | "diff": { 71 | "version": "4.0.2", 72 | "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", 73 | "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", 74 | "dev": true 75 | }, 76 | "make-error": { 77 | "version": "1.3.6", 78 | "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", 79 | "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", 80 | "dev": true 81 | }, 82 | "ts-node": { 83 | "version": "10.2.1", 84 | "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.2.1.tgz", 85 | "integrity": "sha512-hCnyOyuGmD5wHleOQX6NIjJtYVIO8bPP8F2acWkB4W06wdlkgyvJtubO/I9NkI88hCFECbsEgoLc0VNkYmcSfw==", 86 | "dev": true, 87 | "requires": { 88 | "@cspotcode/source-map-support": "0.6.1", 89 | "@tsconfig/node10": "^1.0.7", 90 | "@tsconfig/node12": "^1.0.7", 91 | "@tsconfig/node14": "^1.0.0", 92 | "@tsconfig/node16": "^1.0.2", 93 | "acorn": "^8.4.1", 94 | "acorn-walk": "^8.1.1", 95 | "arg": "^4.1.0", 96 | "create-require": "^1.1.0", 97 | "diff": "^4.0.1", 98 | "make-error": "^1.1.1", 99 | "yn": "3.1.1" 100 | } 101 | }, 102 | "typescript": { 103 | "version": "4.4.3", 104 | "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.4.3.tgz", 105 | "integrity": "sha512-4xfscpisVgqqDfPaJo5vkd+Qd/ItkoagnHpufr+i2QCHBsNYp+G7UAoyFl8aPtx879u38wPV65rZ8qbGZijalA==", 106 | "dev": true 107 | }, 108 | "yn": { 109 | "version": "3.1.1", 110 | "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", 111 | "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", 112 | "dev": true 113 | } 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /SDP-DecoratorPattern/code/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "code", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "keywords": [], 10 | "author": "", 11 | "license": "ISC", 12 | "devDependencies": { 13 | "ts-node": "^10.2.1", 14 | "typescript": "^4.4.3" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /SDP-DecoratorPattern/code/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | /* Visit https://aka.ms/tsconfig.json to read more about this file */ 4 | 5 | /* Basic Options */ 6 | // "incremental": true, /* Enable incremental compilation */ 7 | "target": "es5", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', 'ES2021', or 'ESNEXT'. */ 8 | "module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */ 9 | // "lib": [], /* Specify library files to be included in the compilation. */ 10 | // "allowJs": true, /* Allow javascript files to be compiled. */ 11 | // "checkJs": true, /* Report errors in .js files. */ 12 | // "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', 'react', 'react-jsx' or 'react-jsxdev'. */ 13 | // "declaration": true, /* Generates corresponding '.d.ts' file. */ 14 | // "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */ 15 | // "sourceMap": true, /* Generates corresponding '.map' file. */ 16 | // "outFile": "./", /* Concatenate and emit output to single file. */ 17 | // "outDir": "./", /* Redirect output structure to the directory. */ 18 | // "rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */ 19 | // "composite": true, /* Enable project compilation */ 20 | // "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */ 21 | // "removeComments": true, /* Do not emit comments to output. */ 22 | // "noEmit": true, /* Do not emit outputs. */ 23 | // "importHelpers": true, /* Import emit helpers from 'tslib'. */ 24 | // "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */ 25 | // "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */ 26 | 27 | /* Strict Type-Checking Options */ 28 | "strict": true, /* Enable all strict type-checking options. */ 29 | // "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */ 30 | // "strictNullChecks": true, /* Enable strict null checks. */ 31 | // "strictFunctionTypes": true, /* Enable strict checking of function types. */ 32 | // "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */ 33 | // "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */ 34 | // "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */ 35 | // "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */ 36 | 37 | /* Additional Checks */ 38 | // "noUnusedLocals": true, /* Report errors on unused locals. */ 39 | // "noUnusedParameters": true, /* Report errors on unused parameters. */ 40 | // "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */ 41 | // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */ 42 | // "noUncheckedIndexedAccess": true, /* Include 'undefined' in index signature results */ 43 | // "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an 'override' modifier. */ 44 | // "noPropertyAccessFromIndexSignature": true, /* Require undeclared properties from index signatures to use element accesses. */ 45 | 46 | /* Module Resolution Options */ 47 | // "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */ 48 | // "baseUrl": "./", /* Base directory to resolve non-absolute module names. */ 49 | // "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */ 50 | // "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */ 51 | // "typeRoots": [], /* List of folders to include type definitions from. */ 52 | // "types": [], /* Type declaration files to be included in compilation. */ 53 | // "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */ 54 | "esModuleInterop": true, /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */ 55 | // "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */ 56 | // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ 57 | 58 | /* Source Map Options */ 59 | // "sourceRoot": "", /* Specify the location where debugger should locate TypeScript files instead of source locations. */ 60 | // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ 61 | // "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */ 62 | // "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */ 63 | 64 | /* Experimental Options */ 65 | // "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */ 66 | // "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */ 67 | 68 | /* Advanced Options */ 69 | "skipLibCheck": true, /* Skip type checking of declaration files. */ 70 | "forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */ 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /SDP-FlyweightPattern/README.md: -------------------------------------------------------------------------------- 1 |

2 |

Flyweight Pattern

3 |

4 | 5 | > The Flyweight design pattern is a structural pattern that focuses on optimizing memory usage by sharing common data among multiple objects. It's used when you have a large number of similar objects that can share certain parts of their state, effectively reducing the memory footprint of your application. 6 | 7 | The essence of the Flyweight pattern is all about **sharing**. When you have a lot of similar objects that have parts that can be shared among them, the Flyweight pattern helps you save memory by storing those shared parts separately. This way, you create the heavy parts only once and reuse them for multiple objects. It's like having a bunch of LEGO pieces that you use to build different structures without making duplicates of the same piece. Remember, if you notice a situation where objects have common parts that can be shared, the Flyweight pattern can be a smart way to make your program more efficient. 8 | 9 | *** 10 | 11 | ### The easiest way to understand the intent of the Flyweight pattern is to look at examples of where it is useful. 12 | 13 | The Flyweight design pattern is beneficial in scenarios where you have a large number of objects that share common properties and can be grouped into intrinsic and extrinsic states. This pattern is useful when you need to conserve memory and reduce the overhead associated with creating and managing many similar objects. Here are some cases where the Flyweight pattern can be beneficial: 14 | 15 | 1. **Large Number of Objects**: When you need to create a significant number of objects with similar attributes, and the objects can be categorized into intrinsic (shared) and extrinsic (unique) states. 16 | 17 | 2. **Memory Efficiency**: If the objects have a lot of shared properties or data, using the Flyweight pattern can help reduce memory usage by storing shared data in a centralized way. 18 | 19 | 3. **Performance Optimization**: The pattern can improve performance by minimizing the overhead of object creation and destruction. This is especially useful in resource-constrained environments. 20 | 21 | 4. **Stateless Objects**: When the objects don't have any intrinsic state that varies between instances, the Flyweight pattern can be used to share a single instance of the object. 22 | 23 | 5. **Caching and Reuse**: If the objects are frequently used and the cost of creating them is high, the pattern can help maintain a pool of reusable instances for better performance. 24 | 25 | 6. **User Interface Elements**: In graphical applications, elements such as icons, fonts, and images can be treated as flyweights. Common properties (like appearance) can be shared, while specific properties (like position) are unique. 26 | 27 | 7. **Text Processing**: For text editors or word processors, individual characters can be implemented as flyweights. Character shapes and fonts are shared, while the position and formatting are unique. 28 | 29 | 8. **Game Development**: In video games, reusable objects like particles, bullets, and enemies can be implemented using the Flyweight pattern. Common properties (like graphics) are shared, while specific properties (like position) differ. 30 | 31 | 9. **Network Communication**: In network-related applications, flyweights can be used to represent network connections or data packets. Shared protocol-related data can be centralized, while connection-specific data is unique. 32 | 33 | 10. **Database Systems**: When dealing with database records or result sets, shared metadata (like column names) can be treated as flyweights, while record-specific data is distinct. 34 | 35 | Remember that the Flyweight pattern is most effective when there is a significant amount of shared data among objects and when the cost of object creation and management is relatively high. If objects don't share much data or if object creation is inexpensive, the benefits of the Flyweight pattern may be less pronounced. 36 | 37 | *** 38 | 39 | ### Steps to implementing the Flyweight pattern. 40 | 41 | Let's consider a scenario where we're building a virtual world simulation game. The game world contains various types of trees, each with different attributes. Each tree has its position, size, and type. However, the appearance of the leaves and the trunk's texture can be shared among multiple trees since they're identical. 42 | 43 | > **AGENDA** : Optimizing Memory Usage in a Virtual World Simulation Game; We'll use the Flyweight pattern to optimize memory usage by sharing intrinsic properties of the trees. 44 | 45 | 1. We fist **Identify Similarity**, recognize that many trees share common parts, like their leaves and trunk textures. These parts don't need to be duplicated for every tree. 46 | 47 | 48 | 2. Next we **Divide into Intrinsic and Extrinsic Data:** Divide the tree properties into intrinsic (shared) and extrinsic (unique) data. Intrinsic data is the part that can be shared, like the texture of leaves or the trunk's color. Extrinsic data is unique to each tree, like its position and size. 49 | 50 | 51 | 3. **Create Flyweight Objects:** Create a class for the shared parts of the trees, such as the texture of leaves and trunk. These are the Flyweight objects. They should have methods to modify the intrinsic data and display the part when needed. 52 | ```TS 53 | interface Tree { 54 | display(position: { x: number, y: number }): void; 55 | } 56 | 57 | class PineTree implements Tree { 58 | private texture: string; 59 | private color: string; 60 | private health: number; 61 | private age: number; 62 | private canBearFruit: boolean; 63 | 64 | constructor(texture: string, color: string, health: number, age: number, canBearFruit: boolean) { 65 | this.texture = texture; 66 | this.color = color; 67 | this.health = health; 68 | this.age = age; 69 | this.canBearFruit = canBearFruit; 70 | } 71 | 72 | display(position: { x: number, y: number }): void { 73 | console.log(`Displaying a pine tree at (${position.x},${position.y})`); 74 | console.log(`Texture: ${this.texture}, Color: ${this.color}`); 75 | console.log(`Health: ${this.health}, Age: ${this.age}`); 76 | console.log(`Can Bear Fruit: ${this.canBearFruit}`); 77 | } 78 | } 79 | 80 | class OakTree implements Tree { 81 | private texture: string; 82 | private color: string; 83 | private health: number; 84 | private age: number; 85 | private canBearAcorns: boolean; 86 | 87 | constructor(texture: string, color: string, health: number, age: number, canBearAcorns: boolean) { 88 | this.texture = texture; 89 | this.color = color; 90 | this.health = health; 91 | this.age = age; 92 | this.canBearAcorns = canBearAcorns; 93 | } 94 | 95 | display(position: { x: number, y: number }): void { 96 | console.log(`Displaying an oak tree at (${position.x},${position.y})`); 97 | console.log(`Texture: ${this.texture}, Color: ${this.color}`); 98 | console.log(`Health: ${this.health}, Age: ${this.age}`); 99 | console.log(`Can Bear Acorns: ${this.canBearAcorns}`); 100 | } 101 | } 102 | 103 | ``` 104 | 105 | 4. **Create a Factory:** Implement a Factory or Manager class responsible for creating and managing Flyweight objects. When you need a tree in the game, the factory either retrieves an existing Flyweight object with the required texture or creates a new one if it doesn't exist. 106 | ```TS 107 | class TreeTypeFactory { 108 | private treeTypes: Map = new Map(); 109 | 110 | getTreeType(texture: string, color: string, health: number, age: number, canBearFruit: boolean): TreeType { 111 | const key = this.getTreeTypeKey(texture, color); 112 | 113 | if (!this.treeTypes.has(key)) { 114 | this.treeTypes.set(key, new TreeType(texture, color, health, age, canBearFruit)); 115 | } 116 | 117 | return this.treeTypes.get(key)!; 118 | } 119 | 120 | // ... Other methods 121 | } 122 | ``` 123 | 124 | 125 | 5. **Create Tree Objects:** For each individual tree in the game, create a Tree class that holds both intrinsic and extrinsic data. The intrinsic data (shared parts) is stored by referencing the Flyweight objects created earlier. 126 | ```TS 127 | const treeTypeFactory = new TreeTypeFactory(); 128 | 129 | // Create trees with shared intrinsic properties 130 | const oakTree = { 131 | treeType: treeTypeFactory.getTreeType("oakTexture", "green", 80, 50, false), 132 | position: { x: 10, y: 20 }, 133 | size: { width: 50, height: 100 }, 134 | }; 135 | 136 | const pineTree = { 137 | treeType: treeTypeFactory.getTreeType("pineTexture", "green", 100, 40, true), 138 | position: { x: 30, y: 40 }, 139 | size: { width: 40, height: 80 }, 140 | }; 141 | ``` 142 | 143 | 6. **Display Trees:** When displaying trees in the game, the Tree objects use their intrinsic data (shared parts) from the Flyweight objects. They combine this with their extrinsic data (position, size) to show the complete tree. 144 | ```TS 145 | 146 | oakTree.treeType.display({ x: 25, y: 25 }); 147 | pineTree.treeType.display({ x: 10, y: 20 }); 148 | ``` 149 | By using the Flyweight pattern in this scenario, you save memory and processing time. The shared parts of the trees are created only once and reused among different trees, reducing memory consumption and improving performance. This approach is especially useful when you have a large number of similar objects with common parts. 150 | 151 | *** 152 | 153 | #### How it works 154 | * The client code requests a flyweight object from the flyweight factory, providing it with extrinsic data (such as character position). 155 | * The flyweight factory checks if a flyweight object with the requested intrinsic state (e.g., font type) already exists in its pool. 156 | * If the flyweight object exists, the factory returns it. If not, the factory creates a new flyweight object and adds it to the pool. 157 | * The client uses the flyweight object to render the character, with the extrinsic data provided. 158 | 159 | ### Variations of Flyweight Pattern 160 | 161 | 162 | *** 163 | 164 |

When to use Flyweight pattern over other patterns

165 | 166 | -------------------------------------------------------------------------------- /UML.MD: -------------------------------------------------------------------------------- 1 |
UML, short for Unified Modeling Language, is a visual language filled with drawing notation and semantics used to create models of programs. UML is very important part of developing object oriented software and the software development process. The UML uses mostly graphical notations to express the design of software Designs, patterns and architecture.
2 | 3 | *** 4 | 5 | `This Article is continuation of my previous article about the 'Object' in 'Object Oriented programming'.` 6 | 7 | 8 | {% post midasxiv/object-oriented-programming-dealing-with-changing-requirements-cbh %} 9 | 10 | `This article will give you minimal understanding you need to be able to read the diagram associated with Design Patterns and Design Principles` 11 | 12 | *** 13 | 14 | `link to the repository I maintain regarding this at the bottom of the article.` 15 | 16 | *** 17 | 18 | # Why to Learn UML 19 | 20 | :small_orange_diamond: The UML is not only a better way of describing object-oriented designs. It also forces the designer to think through the relationships between classes in their approach as it needs to be written. 21 | 22 | :small_orange_diamond: Complex applications need collaboration and planning from multiple teams and hence require a clear and concise way to communicate among them. 23 | 24 | ## Unified Modelling language - Basics 25 | 26 | ### :arrow_right: Class Diagram 27 | 28 |
A class is depicted as a rectangle with the class name in bold. Any data that the class defines comes after the class name. Operations appear in normal type below the class attributes. Lines separate the class name from the operations and the operations from the data.
29 | 30 | *** 31 | 32 | ### :arrow_right: Class Attributes Visibility 33 | 34 |
Describes the accessibility of an attribute of a class,these notations must be placed before the member's name.
35 | 36 | | Symbol| Term | Definition | 37 | | :-: | :---------- | :--- | 38 | | `+` | `Public` | `All objects can access this data or method.` 39 | | `-` | `Private` | `Only methods of this class can access this data or method.`| 40 | | `#` | `Protected` | `Only this class and all of its derivations can access this data or method.` | 41 | | `~` | `Package` | `Members of the same class, derived classes, of any other class from the Same package.`| 42 | 43 | | `Access Right`|`public (+)`|`private (-)`| `protected (#)`| `Package (~)` | 44 | | :------------ |:---------: | :-----------: | :-----------: | :-----------: | 45 | | `Members of the same class` | `yes` |`yes` | `yes` | `yes` | 46 | | `Members of derived classes`| `yes` |`no` | `yes` | `yes` | 47 | | `Members of any other class`| `yes` |`no` | `no` | `in same package` | 48 | 49 | 50 | ![class](https://user-images.githubusercontent.com/24829816/72670081-b9f82c80-3a52-11ea-91d1-c575ee525f67.png) 51 | 52 | *** 53 | 54 | ### :arrow_right: Aggregation 55 | 56 |
There are actually two different kinds of has-a relationships. One object can have another object where the contained object is a part of the containing object — or not.
57 | For example a 'Car Showroom' "has" Cars. Cars are not part of 'Car Showroom', but I can still say that a 'Car Showroom' has them. This type of relationship is called aggregation. 58 | 59 |
60 | 61 | 62 | *** 63 | 64 | 65 | ### :arrow_right: Composition 66 | 67 |
The other type of has-a relationship is where the containment means the contained object is a part of the containing object. This type of relationship is also called composition.
68 | A Car has Tires as parts (that is, the Car is made up of Tires and other things). This type of has-a relationship, called composition, is depicted by the filled in diamond.
69 | Both composition and aggregation involve one object containing one or more objects. Composition, however, implies the contained object is a part of the containing object, whereas aggregation means the contained objects are more like a collection of things. 70 |
71 | 72 | *** 73 | 74 | 75 | ### :arrow_right: Dependency 76 | 77 |
78 | Dependency is a weaker form of bond that indicates that one class depends on another because it uses it at some point in time. One class depends on another if the independent class is a parameter variable or local variable of a method of the dependent class.
79 | For example, This diagram shows that a Car uses a 'GasStation'. The uses relationship is depicted by a dashed line with an arrow. This is also called a dependency relationship. 80 |
81 | 82 | *** 83 | 84 | ### :arrow_right: Inheritance 85 | 86 |
Inheritance is a mechanism by which child classes inherit the properties of their parent classes. The easiest way to understand Inheritance is to think of it as a is-a relationship.
87 | for example, Sedan is-a a type of car, Hatchback is-a a type of car just like SUV is-a a type of car
88 | 89 | *** 90 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | /* Basic Options */ 4 | // "incremental": true, /* Enable incremental compilation */ 5 | "target": "es5", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019' or 'ESNEXT'. */ 6 | "module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */ 7 | // "lib": [], /* Specify library files to be included in the compilation. */ 8 | // "allowJs": true, /* Allow javascript files to be compiled. */ 9 | // "checkJs": true, /* Report errors in .js files. */ 10 | // "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */ 11 | // "declaration": true, /* Generates corresponding '.d.ts' file. */ 12 | // "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */ 13 | // "sourceMap": true, /* Generates corresponding '.map' file. */ 14 | // "outFile": "./", /* Concatenate and emit output to single file. */ 15 | // "outDir": "./", /* Redirect output structure to the directory. */ 16 | // "rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */ 17 | // "composite": true, /* Enable project compilation */ 18 | // "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */ 19 | // "removeComments": true, /* Do not emit comments to output. */ 20 | // "noEmit": true, /* Do not emit outputs. */ 21 | // "importHelpers": true, /* Import emit helpers from 'tslib'. */ 22 | // "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */ 23 | // "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */ 24 | 25 | /* Strict Type-Checking Options */ 26 | "strict": true, /* Enable all strict type-checking options. */ 27 | // "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */ 28 | // "strictNullChecks": true, /* Enable strict null checks. */ 29 | // "strictFunctionTypes": true, /* Enable strict checking of function types. */ 30 | // "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */ 31 | // "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */ 32 | // "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */ 33 | // "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */ 34 | 35 | /* Additional Checks */ 36 | // "noUnusedLocals": true, /* Report errors on unused locals. */ 37 | // "noUnusedParameters": true, /* Report errors on unused parameters. */ 38 | // "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */ 39 | // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */ 40 | 41 | /* Module Resolution Options */ 42 | // "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */ 43 | // "baseUrl": "./", /* Base directory to resolve non-absolute module names. */ 44 | // "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */ 45 | // "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */ 46 | // "typeRoots": [], /* List of folders to include type definitions from. */ 47 | // "types": [], /* Type declaration files to be included in compilation. */ 48 | // "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */ 49 | "esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */ 50 | // "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */ 51 | // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ 52 | 53 | /* Source Map Options */ 54 | // "sourceRoot": "", /* Specify the location where debugger should locate TypeScript files instead of source locations. */ 55 | // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ 56 | // "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */ 57 | // "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */ 58 | 59 | /* Experimental Options */ 60 | // "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */ 61 | // "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */ 62 | } 63 | } 64 | --------------------------------------------------------------------------------