├── Creational Patterns ├── Abstract Factory │ ├── TaskAbstractFactory.md │ └── TaskAbstractFactory.swift ├── Builder │ ├── Builder.md │ └── TaskBuilder.swift ├── Factory │ ├── TaskFactory.md │ └── TaskFactory.swift └── Prototype │ ├── Prototype.md │ └── TaskPrototype.swift ├── LICENSE ├── README.md └── Structural Patterns ├── Adapter ├── Adapter.md └── ExternalTaskAdapter.swift └── Bridge ├── Bridge.md ├── TaskExecutionModes.swift └── TaskNotificationMechanisms.swift /Creational Patterns/Abstract Factory/TaskAbstractFactory.md: -------------------------------------------------------------------------------- 1 | # Abstract Factory Design Pattern 2 | 3 | ## Introduction 4 | The Abstract Factory Design Pattern is a creational pattern that extends the concept of factory methods. It provides an interface for creating families of related or dependent objects without specifying their concrete classes. This pattern is particularly useful when a system needs to integrate with multiple families of related products or when it's designed to be extensible with new product families. 5 | 6 | ## Characteristics 7 | 8 | ### 1. Group of Related Products 9 | - Unlike the simple Factory Pattern that creates single products, the Abstract Factory Pattern is used to create families of related or dependent products. 10 | 11 | ### 2. High-Level Abstraction of Object Creation 12 | - The Abstract Factory Pattern abstracts not just the creation of objects but the creation of families of related objects. Clients work with product interfaces and factories, remaining completely unaware of the concrete classes required to instantiate these objects. 13 | 14 | ### 3. Facilitates Consistency Among Products 15 | - Ensures that products that are meant to be used together can be combined without issues. This consistency is hard to achieve with simple factory or constructor methods. 16 | 17 | ### 4. Decoupling and Extensibility 18 | - Like the Factory Pattern, it helps decouple product implementations from the client code. It goes further by allowing easy extension with new product families without modifying existing code, adhering to the Open/Closed Principle. 19 | 20 | ## Use Cases 21 | - When the system needs to be independent of how its products are created, composed, and represented. 22 | - When the system should be configured with one of multiple families of products. 23 | - When a family of related product objects is designed to be used together, and you need to enforce this constraint. 24 | 25 | ## Example in Swift 26 | In our Swift code example, the Abstract Factory Pattern is used to create different types of tasks (`SimpleTask`, `RecurringTask`, `DeadlineTask`). The pattern is implemented through a protocol `TaskFactoryProtocol` and a concrete factory `TaskFactory`. The `TaskFactoryProtocol` defines methods for creating different types of tasks, and `TaskFactory` implements these methods to return the respective task types. 27 | 28 | The `TaskManager` class is responsible for managing tasks using a factory. It can create various types of tasks by calling methods on the factory, which then returns the specific task instances based on the provided `TaskType`. This abstraction allows for easy addition of new task types and task creation processes without modifying the client code that uses the factory. 29 | 30 | For a practical implementation, see the Swift code in [TaskAbstractFactory.swift](./TaskAbstractFactory.swift). 31 | -------------------------------------------------------------------------------- /Creational Patterns/Abstract Factory/TaskAbstractFactory.swift: -------------------------------------------------------------------------------- 1 | // Define a basic protocol for a Task 2 | // This protocol acts as a template for any task, ensuring they all have a title, description, and a way to perform the task. 3 | protocol Task { 4 | var title: String { get set } 5 | var description: String { get set } 6 | func performTask() 7 | } 8 | 9 | // Define the different task types. 10 | // This allows for easy categorisation of tasks into simple, recurring, or deadline-based types. 11 | enum TaskType { 12 | case simple, recurring, deadline 13 | } 14 | 15 | // Concrete Task types implementing the Task protocol. 16 | 17 | // SimpleTask for tasks that are one-off or don't repeat. 18 | final class SimpleTask: Task { 19 | var title: String 20 | var description: String 21 | 22 | init( 23 | title: String, 24 | description: String 25 | ) { 26 | self.title = title 27 | self.description = description 28 | } 29 | 30 | func performTask() { 31 | print("Performing a simple task with title: \(title), and description: \(description)") 32 | } 33 | } 34 | 35 | // RecurringTask for tasks that occur repeatedly. 36 | final class RecurringTask: Task { 37 | var title: String 38 | var description: String 39 | 40 | init( 41 | title: String, 42 | description: String 43 | ) { 44 | self.title = title 45 | self.description = description 46 | } 47 | 48 | func performTask() { 49 | print("Performing a recurring task with title: \(title), and description: \(description)") 50 | } 51 | } 52 | 53 | // DeadlineTask for tasks that need to be completed by a specific date. 54 | final class DeadlineTask: Task { 55 | var title: String 56 | var description: String 57 | var deadline: String // Additional property to store the deadline. 58 | 59 | init( 60 | title: String, 61 | description: String, 62 | deadline: String 63 | ) { 64 | self.title = title 65 | self.description = description 66 | self.deadline = deadline 67 | } 68 | 69 | func performTask() { 70 | print("Performing a task with a deadline (\(deadline)), with title: \(title), and description: \(description)") 71 | } 72 | } 73 | 74 | // Protocol defining methods for creating different types of tasks. 75 | protocol TaskFactoryProtocol { 76 | func createSimpleTask(title: String, description: String) -> Task 77 | func createRecurringTask(title: String, description: String) -> Task 78 | func createDeadlineTask(title: String, description: String, deadline: String) -> Task 79 | } 80 | 81 | // Factory class implementing the TaskFactoryProtocol for creating task instances. 82 | final class TaskFactory: TaskFactoryProtocol { 83 | func createSimpleTask(title: String, description: String) -> Task { 84 | SimpleTask( 85 | title: title, 86 | description: description 87 | ) 88 | } 89 | 90 | func createRecurringTask(title: String, description: String) -> Task { 91 | RecurringTask( 92 | title: title, 93 | description: description 94 | ) 95 | } 96 | 97 | func createDeadlineTask(title: String, description: String, deadline: String) -> Task { 98 | DeadlineTask( 99 | title: title, 100 | description: description, 101 | deadline: deadline 102 | ) 103 | } 104 | } 105 | 106 | // Class responsible for managing tasks using a factory. 107 | final class TaskManager { 108 | private var factory: TaskFactoryProtocol 109 | 110 | init( 111 | factory: TaskFactoryProtocol 112 | ) { 113 | self.factory = factory 114 | } 115 | 116 | func createTask( 117 | type: TaskType, 118 | title: String, 119 | description: String, 120 | deadline: String? = nil 121 | ) -> Task { 122 | 123 | switch type { 124 | case .simple: 125 | factory.createSimpleTask( 126 | title: title, 127 | description: description 128 | ) 129 | case .recurring: 130 | factory.createRecurringTask( 131 | title: title, 132 | description: description 133 | ) 134 | case .deadline: 135 | factory.createDeadlineTask( 136 | title: title, 137 | description: description, 138 | deadline: deadline ?? "" 139 | ) 140 | } 141 | } 142 | 143 | func performTask( 144 | _ task: Task 145 | ) { 146 | task.performTask() 147 | } 148 | } 149 | 150 | // Example usage: 151 | 152 | let manager = TaskManager( 153 | factory: TaskFactory() 154 | ) 155 | 156 | // Creating various types of tasks. 157 | let simpleTask = manager.createTask( 158 | type: .simple, 159 | title: "Write Swift Code", 160 | description: "Develop a new feature using Swift." 161 | ) 162 | 163 | let recurringTask = manager.createTask( 164 | type: .recurring, 165 | title: "Code Review", 166 | description: "Regularly review team's code submissions." 167 | ) 168 | 169 | let deadlineTask = manager.createTask( 170 | type: .deadline, 171 | title: "Project Deadline", 172 | description: "Complete the project for the end-of-year release.", 173 | deadline: "2023-12-31" 174 | ) 175 | 176 | // Storing the tasks in an array and iterating over them to perform each task. 177 | let tasks = [simpleTask, recurringTask, deadlineTask] 178 | 179 | // Perform stored tasks 180 | tasks.forEach( 181 | manager.performTask 182 | ) 183 | -------------------------------------------------------------------------------- /Creational Patterns/Builder/Builder.md: -------------------------------------------------------------------------------- 1 | # Builder Design Pattern 2 | 3 | ## Introduction 4 | The Builder Design Pattern is a creational pattern used to construct a complex object step by step. It separates the construction process of an object from its representation, allowing the same construction process to create different representations. 5 | 6 | ## Characteristics 7 | 8 | ### 1. Step-by-Step Construction 9 | - The Builder Pattern allows building a complex object in a stepwise fashion. It provides control over the construction process. 10 | 11 | ### 2. Encapsulation of Construction Logic 12 | - The pattern encapsulates the way a complex object is constructed, thereby hiding the details from the client. 13 | 14 | ### 3. Creation of Different Representations 15 | - The Builder Pattern allows different representations of the constructed object, enhancing flexibility. 16 | 17 | ## When to Use 18 | 19 | - When the algorithm for creating a complex object should be independent of the parts that make up the object and how they're assembled. 20 | - When the construction process must allow different representations for the constructed object. 21 | - When there's a need to isolate the code for construction and representation of a complex object. 22 | 23 | ## Benefits and Drawbacks 24 | 25 | ### Benefits 26 | - Provides finer control over the construction process. 27 | - Supports constructing complex objects with numerous attributes. 28 | - Improves code readability and maintainability. 29 | 30 | ### Drawbacks 31 | - Can lead to increased code complexity due to the additional builder classes. 32 | - Might introduce additional layers of abstraction, which could complicate the code. 33 | 34 | ## Example in Swift 35 | The Builder Pattern is implemented in the [TaskBuilder.swift](./TaskBuilder.swift) file. This example demonstrates the construction of a `Task` object in a task management system, showcasing the step-by-step building process facilitated by the Builder Pattern. It includes the definition of a `Task` structure, along with the associated `TaskType` and `Priority` enums, and the `TaskBuilder` class that follows the Builder Pattern for creating `Task` instances with various attributes. 36 | -------------------------------------------------------------------------------- /Creational Patterns/Builder/TaskBuilder.swift: -------------------------------------------------------------------------------- 1 | // Task structure representing a single task in the management system. 2 | // It includes essential details like title, type, description, deadline, priority, and assignee. 3 | struct Task { 4 | let title: String 5 | let type: TaskType 6 | let description: String 7 | let deadline: String 8 | let priority: Priority 9 | let assignee: String 10 | } 11 | 12 | // Enum for differentiating task types. This helps categorize tasks based on their nature or requirement. 13 | enum TaskType { 14 | case simple, recurring, deadline, unknown // 'unknown' can be used as a default or placeholder. 15 | } 16 | 17 | // Enum for setting the priority of a task. It helps in task prioritization and management. 18 | enum Priority { 19 | case low, medium, high 20 | } 21 | 22 | // Protocol defining the contract for a Task builder. 23 | // It specifies methods to set various properties of a Task. 24 | protocol TaskBuilderProtocol { 25 | func setTitle(_ title: String) -> TaskBuilder 26 | func setDescription(_ description: String) -> TaskBuilder 27 | func setDeadline(_ deadline: String) -> TaskBuilder 28 | func setPriority(_ priority: Priority) -> TaskBuilder 29 | func setAssignee(_ assignee: String) -> TaskBuilder 30 | func build() -> Task // Method to construct the final Task object. 31 | } 32 | 33 | // Task builder class for creating a Task. It implements the TaskBuilderProtocol. 34 | final class TaskBuilder: TaskBuilderProtocol { 35 | // Private properties holding the state of the building task. 36 | private var title: String = "New Task" 37 | private var type: TaskType = .unknown 38 | private var description: String = "No description" 39 | private var deadline: String = "No Deadline" 40 | private var priority: Priority = .medium 41 | private var assignee: String = "Unassigned" 42 | 43 | // Each of these methods sets a specific attribute of a task and returns the builder itself for method chaining. 44 | func setTitle(_ title: String) -> TaskBuilder { 45 | self.title = title 46 | return self 47 | } 48 | 49 | func setType(_ type: TaskType) -> TaskBuilder { 50 | self.type = type 51 | return self 52 | } 53 | 54 | func setDescription(_ description: String) -> TaskBuilder { 55 | self.description = description 56 | return self 57 | } 58 | 59 | func setDeadline(_ deadline: String) -> TaskBuilder { 60 | self.deadline = deadline 61 | return self 62 | } 63 | 64 | func setPriority(_ priority: Priority) -> TaskBuilder { 65 | self.priority = priority 66 | return self 67 | } 68 | 69 | func setAssignee(_ assignee: String) -> TaskBuilder { 70 | self.assignee = assignee 71 | return self 72 | } 73 | 74 | // Finalizes the construction of the Task object and returns it. 75 | // This method uses the current state of the builder to create a new Task instance. 76 | func build() -> Task { 77 | Task( 78 | title: title, 79 | type: type, 80 | description: description, 81 | deadline: deadline, 82 | priority: priority, 83 | assignee: assignee 84 | ) 85 | } 86 | } 87 | 88 | // Demonstrating how to use the TaskBuilder to create a Task instance. 89 | let taskBuilder = TaskBuilder() 90 | let task = taskBuilder 91 | .setTitle("Implement Builder Pattern") 92 | .setType(.deadline) 93 | .setDescription("Create a builder pattern example for the Task Management System") 94 | .setDeadline("2023-12-31") 95 | .setPriority(.high) 96 | .setAssignee("Roberto G.") 97 | .build() 98 | -------------------------------------------------------------------------------- /Creational Patterns/Factory/TaskFactory.md: -------------------------------------------------------------------------------- 1 | # Factory Design Pattern 2 | 3 | ## Introduction 4 | The Factory Design Pattern is a creational pattern that provides an interface for creating objects in a superclass but allows subclasses to alter the type of objects that will be created. This pattern is particularly useful when a system needs to be independent from the way its objects are created, composed, and represented. 5 | 6 | ## Characteristics 7 | 8 | ### 1. Object Creation Abstraction 9 | - The Factory Pattern abstracts the process of object creation from the client. This means that the client does not need to know the exact class that needs to be instantiated. 10 | 11 | ### 2. Encapsulation of Object Creation 12 | - All details about object creation are encapsulated within the factory. This centralises the creation logic, making the code more maintainable. 13 | 14 | ### 3. Easy to Extend 15 | - Adding new types of products requires modifying the factory, but does not necessitate changes in the client code. This adheres to the Open/Closed Principle, as the code is open for extension but closed for modification. 16 | 17 | ### 4. Decoupling 18 | - The Factory Pattern helps to decouple the implementation of the product from its use. The client is only aware of the interfaces, not the concrete implementations, reducing the system's overall coupling. 19 | 20 | ## Use Cases 21 | - When a class does not know what subclasses will be required to create. 22 | - When a class wants its subclasses to specify the objects to be created. 23 | - When the creation logic of objects needs to be independent of the system's composition. 24 | 25 | ## Example in Swift 26 | In our Swift code example, we used the Factory Pattern to create different types of tasks (`SimpleTask`, `RecurringTask`, `DeadlineTask`). The `TaskFactory` class is responsible for creating these task instances based on the provided `TaskType`. This abstraction allows for easy addition of new task types without modifying the client code that uses the factory. 27 | 28 | For a practical implementation, see the Swift code in [TaskFactory.swift](./TaskFactory.swift). 29 | -------------------------------------------------------------------------------- /Creational Patterns/Factory/TaskFactory.swift: -------------------------------------------------------------------------------- 1 | // Define a basic protocol for a Task 2 | // This protocol acts as a template for any task, ensuring they all have a title, description, and a way to perform the task. 3 | protocol Task { 4 | var title: String { get set } 5 | var description: String { get set } 6 | func performTask() 7 | } 8 | 9 | // Define the different task types. 10 | // This allows for easy categorisation of tasks into simple, recurring, or deadline-based types. 11 | enum TaskType { 12 | case simple, recurring, deadline 13 | } 14 | 15 | // Concrete Task types implementing the Task protocol. 16 | 17 | // SimpleTask for tasks that are one-off or don't repeat. 18 | final class SimpleTask: Task { 19 | var title: String 20 | var description: String 21 | 22 | init( 23 | title: String, 24 | description: String 25 | ) { 26 | self.title = title 27 | self.description = description 28 | } 29 | 30 | func performTask() { 31 | print("Performing a simple task with title: \(title), and description: \(description)") 32 | } 33 | } 34 | 35 | // RecurringTask for tasks that occur repeatedly. 36 | final class RecurringTask: Task { 37 | var title: String 38 | var description: String 39 | 40 | init( 41 | title: String, 42 | description: String 43 | ) { 44 | self.title = title 45 | self.description = description 46 | } 47 | 48 | func performTask() { 49 | print("Performing a recurring task with title: \(title), and description: \(description)") 50 | } 51 | } 52 | 53 | // DeadlineTask for tasks that need to be completed by a specific date. 54 | final class DeadlineTask: Task { 55 | var title: String 56 | var description: String 57 | var deadline: String // Additional property to store the deadline. 58 | 59 | init( 60 | title: String, 61 | description: String, 62 | deadline: String 63 | ) { 64 | self.title = title 65 | self.description = description 66 | self.deadline = deadline 67 | } 68 | 69 | func performTask() { 70 | print("Performing a task with a deadline (\(deadline)), with title: \(title), and description: \(description)") 71 | } 72 | } 73 | 74 | // Task Factory to create tasks based on the type. 75 | // This class uses a factory method pattern to simplify task creation. 76 | final class TaskFactory { 77 | static func createTask( 78 | type: TaskType, 79 | title: String, 80 | description: String, 81 | deadline: String? = nil 82 | ) -> Task { 83 | 84 | switch type { 85 | case .simple: 86 | return SimpleTask(title: title, description: description) 87 | case .recurring: 88 | return RecurringTask(title: title, description: description) 89 | case .deadline: 90 | return DeadlineTask(title: title, description: description, deadline: deadline ?? "") 91 | } 92 | } 93 | } 94 | 95 | // Example Usage: 96 | // Creating various tasks using the TaskFactory and then performing them. 97 | 98 | let simpleTask = TaskFactory.createTask( 99 | type: .simple, 100 | title: "Write Swift Code", 101 | description: "Develop a new feature using Swift." 102 | ) 103 | 104 | let recurringTask = TaskFactory.createTask( 105 | type: .recurring, 106 | title: "Code Review", 107 | description: "Regularly review team's code submissions." 108 | ) 109 | 110 | let deadlineTask = TaskFactory.createTask( 111 | type: .deadline, 112 | title: "Project Deadline", 113 | description: "Complete the project for the end-of-year release.", 114 | deadline: "2023-12-31" 115 | ) 116 | 117 | // Storing the tasks in an array and iterating over them to perform each task. 118 | let tasks = [simpleTask, recurringTask, deadlineTask] 119 | 120 | tasks.forEach { 121 | $0.performTask() 122 | } 123 | -------------------------------------------------------------------------------- /Creational Patterns/Prototype/Prototype.md: -------------------------------------------------------------------------------- 1 | # Prototype Creational Pattern 2 | 3 | ## Introduction 4 | The Prototype Creational Pattern is a design pattern that enables creating new objects by cloning an existing object, known as the prototype. This pattern is useful in scenarios where object creation is costly, and a similar object already exists. 5 | 6 | ## Characteristics 7 | 8 | ### 1. Cloning Mechanism 9 | - The core of the Prototype Pattern is the cloning mechanism, where each object is capable of creating a duplicate of itself. 10 | 11 | ### 2. Reducing Creation Complexity 12 | - The pattern simplifies object creation, particularly when dealing with complex object structures or costly instantiation processes. 13 | 14 | ### 3. Flexibility in Object Variation 15 | - It provides flexibility in creating varied objects, allowing modifications after cloning to adapt to specific needs. 16 | 17 | ### 4. Avoiding Subclassing 18 | - Unlike other creational patterns, the Prototype Pattern avoids the need for subclassing, instead relying on object composition. 19 | 20 | ## Use Cases 21 | - When the types of objects to create are determined dynamically at runtime. 22 | - In situations where reducing the overhead of new instantiation is crucial. 23 | - When a system should be independent of how its products are created, composed, and represented. 24 | 25 | ## Example in Swift 26 | In the provided Swift code example, we demonstrate the Prototype Pattern using a `Task` struct. Each `Task` instance can create a clone of itself, simplifying the creation of new task instances with similar attributes. 27 | 28 | For a practical implementation, see the Swift code in [TaskPrototype.swift](./TaskPrototype.swift). 29 | -------------------------------------------------------------------------------- /Creational Patterns/Prototype/TaskPrototype.swift: -------------------------------------------------------------------------------- 1 | // Protocol for cloning 2 | protocol TaskPrototype { 3 | func clone() -> TaskPrototype 4 | } 5 | 6 | // Enum for differentiating task types. This helps categorize tasks based on their nature or requirement. 7 | enum TaskType { 8 | case simple, recurring, deadline, unknown // 'unknown' can be used as a default or placeholder. 9 | } 10 | 11 | // Enum for setting the priority of a task. It helps in task prioritization and management. 12 | enum Priority { 13 | case low, medium, high, unknown 14 | } 15 | 16 | // Base struct for tasks 17 | class Task: TaskPrototype { 18 | var title: String 19 | var type: TaskType 20 | var description: String 21 | var priority: Priority 22 | var deadline: String? 23 | var assignee: String 24 | 25 | init(title: String, type: TaskType, description: String, priority: Priority, deadline: String?, assignee: String) { 26 | self.title = title 27 | self.type = type 28 | self.description = description 29 | self.priority = priority 30 | self.deadline = deadline 31 | self.assignee = assignee 32 | } 33 | 34 | func clone() -> TaskPrototype { 35 | Task( 36 | title: self.title, 37 | type: self.type, 38 | description: self.description, 39 | priority: self.priority, 40 | deadline: self.deadline, 41 | assignee: self.assignee 42 | ) 43 | } 44 | } 45 | 46 | // Extended task type with additional properties 47 | final class ExtendedTask: Task { 48 | var attachments: [String] 49 | 50 | init( 51 | title: String, 52 | type: TaskType, 53 | description: String, 54 | priority: Priority, 55 | deadline: String?, 56 | assignee: String, 57 | attachments: [String] = [] 58 | ) { 59 | self.attachments = attachments 60 | super.init( 61 | title: title, 62 | type: type, 63 | description: description, 64 | priority: priority, 65 | deadline: deadline, 66 | assignee: assignee 67 | ) 68 | } 69 | 70 | override func clone() -> TaskPrototype { 71 | ExtendedTask( 72 | title: self.title, 73 | type: self.type, 74 | description: self.description, 75 | priority: self.priority, 76 | deadline: self.deadline, 77 | assignee: self.assignee, 78 | attachments: self.attachments 79 | ) 80 | } 81 | } 82 | 83 | // Original instances 84 | let originalBasicTask = Task( 85 | title: "Basic Task", 86 | type: .simple, 87 | description: "This is a basic task", 88 | priority: .medium, 89 | deadline: "2023-12-10", 90 | assignee: "Roberto G" 91 | ) 92 | 93 | let originalExtendedTask = ExtendedTask( 94 | title: "Extended Task", 95 | type: .deadline, 96 | description: "This is an extended task", 97 | priority: .high, 98 | deadline: "2023-12-15", 99 | assignee: "Roberto G", 100 | attachments: ["initialFile.doc"] 101 | ) 102 | 103 | // Cloning and updating attributes 104 | let clonedBasicTask = originalBasicTask.clone() as? Task 105 | // Update some attributes of the cloned basic task 106 | clonedBasicTask?.priority = .high 107 | clonedBasicTask?.deadline = "2023-12-12" 108 | 109 | let clonedExtendedTask = originalExtendedTask.clone() as? ExtendedTask 110 | // Update some attributes of the cloned extended task 111 | clonedExtendedTask?.assignee = "John Doe" 112 | clonedExtendedTask?.attachments.append("additionalFile.txt") 113 | 114 | // Output to verify the cloning and updates 115 | print(""" 116 | Original Basic Task Title: \(originalBasicTask.title), 117 | Priority: \(originalBasicTask.priority) 118 | """) 119 | print(""" 120 | Cloned Basic Task Title: \(clonedBasicTask?.title ?? "Unknown Title"), 121 | Priority: \(clonedBasicTask?.priority ?? .unknown) 122 | """) 123 | 124 | print(""" 125 | Original Extended Task Title: \(originalExtendedTask.title), 126 | Attachments: \(originalExtendedTask.attachments) 127 | """) 128 | print(""" 129 | Cloned Extended Task Title: \(clonedExtendedTask?.title ?? "Unknown Title"), 130 | Attachments: \(clonedExtendedTask?.attachments ?? []) 131 | """) 132 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Roberto Gómez Muñoz 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 📘 Swift Design Patterns Repository 2 | 3 | ## 🌟 Introduction 4 | This repository is dedicated to exploring various design patterns used in Swift programming. It serves as a guide for both novice and experienced developers to understand and implement design patterns effectively in their Swift projects. 5 | 6 | ### 🏗 Creational Patterns 7 | These patterns are all about class instantiation. They can be divided into class-creation patterns and object-creational patterns. 8 | - 🏭 **Factory Method** - [TaskFactory.swift](./Creational%20Patterns/Factory/TaskFactory.md). 9 | - 🏭 **Abstract Factory** - [TaskAstractFactory.swift](./Creational%20Patterns/Abstract%20Factory/TaskAbstractFactory.md). 10 | - 🛠 **Builder** - [TaskBuilder.swift](./Creational%20Patterns/Builder/Builder.md). 11 | - 🤖 **Prototype** - [TaskPrototype.swift](./Creational%20Patterns/Prototype/Prototype.md). 12 | 13 | ### 🌉 Structural Patterns 14 | These patterns are concerned with how classes and objects are composed to form larger structures. 15 | - 🔌 **Adapter** - [ExternalTaskFactory.swift](./Structural%20Patterns/Adapter/Adapter.md). 16 | - 🌁 **Bridge** - [Update scheduled in sequence](#) 🚧 - We are actively working on this and will update it asap!. 17 | - 🧱 **Composite** - [Update scheduled in sequence](#) 18 | - 🎨 **Decorator** - [Update scheduled in sequence](#) 19 | - 🏢 **Facade** - [Update scheduled in sequence](#) 20 | - 🪶 **Flyweight** - [Update scheduled in sequence](#) 21 | - 🛡️ **Proxy** - [Update scheduled in sequence](#) 22 | 23 | ### 🧠 Behavioral Patterns 24 | These patterns are concerned with algorithms and the assignment of responsibilities between objects. 25 | - 👀 **Observer** - [Update scheduled in sequence](#) 26 | - 🤝 **Mediator** - [Update scheduled in sequence](#) 27 | - 👣 **Visitor** - [Update scheduled in sequence](#) 28 | - 💻 **Command** - [Update scheduled in sequence](#) 29 | - 📊 **State** - [Update scheduled in sequence](#) 30 | - 🕹️ **Strategy** - [Update scheduled in sequence](#) 31 | - 📜 **Memento** - [Update scheduled in sequence](#) 32 | 33 | ## 📚 Additional Resources 34 | - 📘 [Swift Documentation](https://swift.org/documentation/) 35 | 36 | ## 📞 Contact 37 | 💼 Feel free to connect with me on [LinkedIn](https://www.linkedin.com/in/robertogomezm/). 38 | 39 | ## 📜 License 40 | This project is licensed under the MIT License - see the [LICENSE.md](LICENSE.md) file for details. 41 | -------------------------------------------------------------------------------- /Structural Patterns/Adapter/Adapter.md: -------------------------------------------------------------------------------- 1 | # Adapter Design Pattern 2 | 3 | ## Introduction 4 | 5 | The Adapter Design Pattern is a structural pattern that allows objects with incompatible interfaces to work together. It acts as a bridge between two different interfaces or classes, enabling them to communicate without modifying their existing code. This pattern is particularly useful when integrating new features, APIs, or systems that do not match the existing system's interface. 6 | 7 | ## Characteristics 8 | 9 | 1. **Interface Compatibility:** The Adapter Pattern makes two different interfaces compatible without changing their existing code. This promotes reusability and flexibility. 10 | 11 | 2. **Single Responsibility Principle:** It follows the Single Responsibility Principle by separating the conversion or adaptation logic into its own class, thereby keeping the system clean and organized. 12 | 13 | 3. **Enhanced Flexibility:** By decoupling the client and the class of the object to be adapted, it enhances the system's flexibility, allowing for functionality to be added or changed without affecting existing code. 14 | 15 | 4. **Simplifies Integration:** It simplifies the integration of classes that couldn't otherwise work together due to incompatible interfaces. This is particularly useful when dealing with third-party libraries or legacy systems. 16 | 17 | ## Use Cases 18 | 19 | - When you want to use an existing class, and its interface does not match the one you need. 20 | - When you want to create a reusable class that cooperates with classes that don't necessarily have compatible interfaces. 21 | - In the integration of new features, APIs, or systems without disturbing the existing infrastructure. 22 | - When you need to provide several different interfaces to the same class. 23 | 24 | ## Example in Swift 25 | 26 | In our Swift example, we demonstrated the Adapter Pattern by integrating an `ExternalTaskService` with a different interface (`taskName`, `taskDetail`, `isCompleted`) into an existing system expecting a `Task` protocol (`title`, `description`). The `ExternalTaskAdapter` served as a bridge, adapting the `ExternalTaskService` to the `Task` protocol, enabling seamless integration without altering the original code or the external service. 27 | 28 | For a practical implementation, see the Swift code in [ExternalTaskAdapter.swift](./ExternalTaskAdapter.swift). 29 | -------------------------------------------------------------------------------- /Structural Patterns/Adapter/ExternalTaskAdapter.swift: -------------------------------------------------------------------------------- 1 | // Define the basic Task protocol for the in-house system. 2 | protocol Task { 3 | var title: String { get } 4 | var description: String { get } 5 | func performTask() 6 | } 7 | 8 | // ExternalTaskService is a modern, third-party task management system. 9 | // This service has its unique interface for handling tasks. 10 | class ExternalTaskService { 11 | var taskName: String 12 | var taskDetail: String 13 | var isCompleted: Bool 14 | 15 | init(taskName: String, taskDetail: String, isCompleted: Bool) { 16 | self.taskName = taskName 17 | self.taskDetail = taskDetail 18 | self.isCompleted = isCompleted 19 | } 20 | 21 | func markAsComplete() { 22 | self.isCompleted = true 23 | print("Task '\(taskName)' marked as complete. Detail: \(taskDetail), Completed: \(isCompleted)") 24 | } 25 | } 26 | 27 | // TaskAdapter adapts ExternalTaskService to be compatible with the Task protocol. 28 | // This allows ExternalTaskService tasks to be treated as in-house Task objects. 29 | struct ExternalTaskAdapter: Task { 30 | private var externalTask: ExternalTaskService 31 | 32 | var title: String { 33 | return externalTask.taskName 34 | } 35 | 36 | var description: String { 37 | return externalTask.taskDetail 38 | } 39 | 40 | init(externalTask: ExternalTaskService) { 41 | self.externalTask = externalTask 42 | } 43 | 44 | func performTask() { 45 | externalTask.markAsComplete() 46 | } 47 | } 48 | 49 | // Example Usage: 50 | 51 | // Creating an instance of ExternalTaskService 52 | let externalServiceTask = ExternalTaskService( 53 | taskName: "API Integration", 54 | taskDetail: "Integrate external task management API.", 55 | isCompleted: false 56 | ) 57 | 58 | // Adapting the external service task to fit the in-house Task protocol. 59 | var adaptedTask = ExternalTaskAdapter(externalTask: externalServiceTask) 60 | 61 | // Now, the external service task can be used just like any other in-house Task. 62 | adaptedTask.performTask() 63 | -------------------------------------------------------------------------------- /Structural Patterns/Bridge/Bridge.md: -------------------------------------------------------------------------------- 1 | # Bridge Design Pattern 2 | 3 | ## Introduction 4 | 5 | The Bridge Design Pattern is a structural design pattern that separates an abstraction from its implementation, allowing them to be varied independently. It enhances modularity and readability in complex systems by decoupling functional abstraction from its implementation details. This pattern is particularly beneficial in scenarios where system components need to be independently extended or modified over time. 6 | 7 | ## Characteristics 8 | 9 | 1. **Abstraction-Implementation Separation:** The Bridge Pattern separates the high-level operations from the implementation that executes those operations. This separation aids in reducing complexity and improving code maintainability. 10 | 11 | 2. **Enhanced Extensibility:** It allows both the abstraction and its implementation to be extended independently. New abstractions and implementations can be introduced without affecting each other. 12 | 13 | 3. **Open/Closed Principle:** Aligns with the Single Responsibility Principle by segregating the abstraction (the interface the client interacts with) from its implementation (the concrete operations). This keeps the system organized and focused. 14 | 15 | 4. **Improved Flexibility:** Offers flexibility in changing and mixing implementations. It is especially useful in scenarios where implementation details are expected to change frequently or need to adapt to changing requirements. 16 | 17 | 5. **Open/Closed Principle:** The Bridge Pattern uses the Open/Closed Principle by allowing systems to be open for extension but closed for modification. This means that you can introduce new abstractions and implementations without changing the existing codebase, promoting scalability and reducing the risk of bugs. 18 | 19 | ## Use Cases 20 | 21 | - When you want to decouple an abstraction from its implementation so that they can be developed, extended, and operated independently. 22 | - When changes in the implementation of an abstraction should not impact clients. 23 | - When you aim to share an implementation among multiple abstractions. 24 | - In situations where class extensions are impractical through inheritance, typically due to an explosion of subclasses. 25 | 26 | ## Examples in Swift 27 | 28 | ### Example 1: Task Execution Modes 29 | Demonstrates asynchronous and synchronous execution of tasks using the Bridge Pattern. By abstracting the execution logic (`ExecutionMode`) from the task itself (`MyTask`), the system allows for flexible task execution strategies without altering the task's definition. [TaskExecutionModes.swift](./TaskExecutionModes.swift) 30 | 31 | ### Example 2: Task Notification Mechanisms 32 | Explores sending notifications for tasks through different mechanisms (Email, Messaging) using the Bridge Pattern. It separates the notification mechanism (`NotificationMechanism`) from the task, enabling easy integration of new notification methods. [TaskNotificationMechanisms.swift](./TaskNotificationMechanisms.swift) 33 | 34 | ### Example 3: Task Priority Management 35 | Illustrates assigning priorities (High, Medium, Low) to tasks using different strategies, showcasing another application of the Bridge Pattern. It decouples the priority assignment strategy from the task, facilitating the introduction of new prioritization algorithms. [TaskPriorityManagement.swift]() 🚧🛠️ Work in Progress! 36 | 37 | These examples highlight the Bridge Design Pattern's utility in creating scalable, maintainable, and extensible systems by effectively managing the interdependencies between different parts of a system. 38 | -------------------------------------------------------------------------------- /Structural Patterns/Bridge/TaskExecutionModes.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | // Task Protocol - Changed the protocol name used in the past examples to "MyTask" to avoid 4 | // issues with the Swift's own concurrency construct, Task. 5 | protocol MyTask { 6 | var title: String { get } 7 | var description: String { get } 8 | func performTask() async 9 | } 10 | 11 | // ExecutionMode Protocol (Implementor) - serves as the bridge between the task and how it's executed 12 | // allowing for flexible task execution strategies 13 | protocol ExecutionMode { 14 | func execute(task: MyTask) async 15 | } 16 | 17 | // Concrete Implementor for Asynchronous Execution 18 | final class AsyncExecution: ExecutionMode { 19 | func execute(task: MyTask) async { 20 | print("Asynchronous Task: \(task.title) execution starts") 21 | // Simulating a network call or a time-consuming operation 22 | // Waiting for 2 seconds 23 | await Task.sleep(2_000_000_000) 24 | 25 | // Now perform the task 26 | await task.performTask() 27 | print("Asynchronous Task: \(task.title) execution end") 28 | } 29 | } 30 | 31 | // Concrete Implementor for Synchronous Execution 32 | final class SyncExecution: ExecutionMode { 33 | func execute(task: MyTask) async { 34 | print("Synchronous Task: \(task.title) execution starts") 35 | await task.performTask() 36 | print("Synchronous Task: \(task.title) execution end") 37 | } 38 | } 39 | 40 | // Task Abstraction 41 | final class GenericTask: MyTask { 42 | var title: String 43 | var description: String 44 | var executionMode: ExecutionMode? 45 | 46 | init( 47 | title: String, 48 | description: String, 49 | executionMode: ExecutionMode? = nil 50 | ) { 51 | self.title = title 52 | self.description = description 53 | self.executionMode = executionMode 54 | } 55 | 56 | func performTask() async { 57 | print("Performing Task: \(title) - \(description)") 58 | } 59 | 60 | func execute() async { 61 | await executionMode?.execute(task: self) 62 | } 63 | } 64 | 65 | // Usage Example 66 | func main() async { 67 | let task1 = GenericTask( 68 | title: "Update Database", 69 | description: "Perform database migration.", 70 | executionMode: SyncExecution() 71 | ) 72 | await task1.execute() 73 | 74 | let task2 = GenericTask( 75 | title: "Fetch Remote Data", 76 | description: "Download data from API.", 77 | executionMode: AsyncExecution() 78 | ) 79 | await task2.execute() 80 | } 81 | 82 | Task { 83 | await main() 84 | } 85 | -------------------------------------------------------------------------------- /Structural Patterns/Bridge/TaskNotificationMechanisms.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | // Task Protocol - Changed the protocol name used in the past examples to "MyTask" to avoid 4 | // issues with the Swift's own concurrency construct, Task. 5 | protocol MyTask { 6 | var title: String { get } 7 | func performTask() async -> String // Now returns a String describing the task result. I am making this change to try to provide more information to the end user. 8 | } 9 | 10 | // Concrete MyTask Implementation 11 | struct ReportGenerationMyTask: MyTask { 12 | var title: String 13 | 14 | func performTask() async -> String { 15 | print("\(title) Generating report...") 16 | do { 17 | try await Task.sleep(nanoseconds: 1_000_000_000) // Simulate time-consuming task 18 | return "\(title) Report generated successfully." // Return a success message 19 | } catch { 20 | return "\(title) Task was cancelled." // Return a cancellation message 21 | } 22 | } 23 | } 24 | 25 | // Notification Mechanism Protocol (Implementor) 26 | protocol NotificationMechanism { 27 | func sendNotification(taskTitle: String, message: String) async 28 | } 29 | 30 | // Concrete Implementors for Notification Mechanisms 31 | final class EmailNotification: NotificationMechanism { 32 | func sendNotification(taskTitle: String, message: String) async { 33 | print("Sending email for '\(taskTitle)': \(message)") 34 | 35 | // Add the specific code to send the notification by email 36 | } 37 | } 38 | 39 | final class MessagingNotification: NotificationMechanism { 40 | func sendNotification(taskTitle: String, message: String) async { 41 | print("Sending messaging notification for '\(taskTitle)': \(message)") 42 | 43 | // Add the specific code to send the notification by message 44 | } 45 | } 46 | 47 | // Usage Example 48 | func main() async { 49 | let task = ReportGenerationMyTask(title: "End-of-Year Financial Report") 50 | let taskResult = await task.performTask() 51 | 52 | // Choose notification mechanism 53 | let emailNotifier = EmailNotification() 54 | let messageNotifier = MessagingNotification() 55 | 56 | // Send notifications with task result 57 | await emailNotifier.sendNotification(taskTitle: task.title, message: taskResult) 58 | await messageNotifier.sendNotification(taskTitle: task.title, message: taskResult) 59 | } 60 | 61 | Task { 62 | await main() 63 | } 64 | --------------------------------------------------------------------------------