{"id":18762544,"url":"https://github.com/milovantomasevic/python-design-patterns","last_synced_at":"2025-04-13T03:32:14.561Z","repository":{"id":103463308,"uuid":"281314450","full_name":"MilovanTomasevic/Python-Design-Patterns","owner":"MilovanTomasevic","description":"Python Design Patterns","archived":false,"fork":false,"pushed_at":"2021-04-14T20:22:31.000Z","size":2319,"stargazers_count":19,"open_issues_count":0,"forks_count":4,"subscribers_count":0,"default_branch":"master","last_synced_at":"2025-03-26T21:38:00.728Z","etag":null,"topics":["adapter-pattern","bridge-pattern","builder-pattern","command-pattern","composite-pattern","decorator-pattern","design-patterns","facade-pattern","factory-pattern","flyweight-pattern","prototype-pattern","proxy-pattern","python","singleton-pattern","strategy-pattern"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/MilovanTomasevic.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-07-21T06:28:30.000Z","updated_at":"2024-08-11T10:24:47.000Z","dependencies_parsed_at":null,"dependency_job_id":"9ffdda26-6c74-4a66-8168-b7b0a980cbfd","html_url":"https://github.com/MilovanTomasevic/Python-Design-Patterns","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MilovanTomasevic%2FPython-Design-Patterns","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MilovanTomasevic%2FPython-Design-Patterns/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MilovanTomasevic%2FPython-Design-Patterns/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MilovanTomasevic%2FPython-Design-Patterns/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/MilovanTomasevic","download_url":"https://codeload.github.com/MilovanTomasevic/Python-Design-Patterns/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248659698,"owners_count":21141161,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["adapter-pattern","bridge-pattern","builder-pattern","command-pattern","composite-pattern","decorator-pattern","design-patterns","facade-pattern","factory-pattern","flyweight-pattern","prototype-pattern","proxy-pattern","python","singleton-pattern","strategy-pattern"],"created_at":"2024-11-07T18:21:53.163Z","updated_at":"2025-04-13T03:32:14.554Z","avatar_url":"https://github.com/MilovanTomasevic.png","language":"Python","readme":"# Python Design Patterns\r\n\r\n## Description\r\n\r\n- This repository contains an overview of the Gang of Four (GoF) design patterns with modern-day variations, adjustments, and discussions in Python.\r\n\r\n## Learning Objectives\r\n\r\n- SOLID Design Principles:\r\n  - [Single Responsibility Principle](/src/1_patterns/1_SOLIDDesignPrinciples/1_SingleResponsibility/srp.py)\r\n  - [Open-Closed Principle](/src/1_patterns/1_SOLIDDesignPrinciples/2_Open-Closed/ocp.py)\r\n  - [Liskov Substitution Principle](/src/1_patterns/1_SOLIDDesignPrinciples/3_LiskovSubstitution/lsp.py)\r\n  - [Interface Segregation Principle](/src/1_patterns/1_SOLIDDesignPrinciples/4_InterfaceSegregation/isp.py)\r\n  - [Dependency Inversion Principle](/src/1_patterns/1_SOLIDDesignPrinciples/5_DependencyInversion/dip.py)\r\n- Creational Design Patterns:\r\n  - [Builder](/src/1_patterns/2_CreationalPatterns/1_Builder/)\r\n    - A builder is a separate component for building an object\r\n    - Can either give builder an initializer or return it via a static function\r\n    - To make builder fluent, return self\r\n    - Different facets of an object can be built with different builders working in tandem via a base class\r\n  - [Factories (Factory Method and Abstract Factory)](/src/1_patterns/2_CreationalPatterns/2_Factories/)\r\n    - A factory method is a static method that creates object\r\n    - A factory is an entity that can take care of object creation\r\n    - A factory can be external or reside inside the object as an inner class\r\n    - Hierarchies of factories can be used to create related objects\r\n  - [Prototype](/src/1_patterns/2_CreationalPatterns/3_Prototype/)\r\n    - To implement a prototype, partially construct an object and store it somewhere\r\n    - Deep copy the prototype\r\n    - Customize the resulting instance\r\n    - A factory provides a convenient API for using prototypes\r\n  - [Singleton](/src/1_patterns/2_CreationalPatterns/4_Singleton/)\r\n    - Different realizations of Singleton: custom allocator, decorator, metaclass\r\n    - Laziness is easy, just init on first request\r\n    - Monostate variation\r\n    - Testability issues\r\n- Structural Design Patterns:\r\n  - [Adapter](/src/1_patterns/3_StructuralPatterns/1_Adapter/)\r\n    - Implementing an Adapter is easy\r\n    - Determine the API you have and the API you need\r\n    - Create a component which aggregates (has a reference to, ...) the adaptee\r\n    - Intermediate representations can pile up: use caching and other optimizations\r\n  - [Bridge](/src/1_patterns/3_StructuralPatterns/2_Bridge/1_bridge.py)\r\n    - Decouple abstraction from implementation\r\n    - Both can exist as hierarchies\r\n    - A stronger form of encapsulation\r\n  - [Composite](/src/1_patterns/3_StructuralPatterns/3_Composite/)\r\n    - Objects can use other objects via inheritance/composition\r\n    - Some composed and singular objects need similar/identical behaviors\r\n    - Composite design pattern lets us treat both types of objects uniformly\r\n    - Python supports iteration with \\_\\_iter\\_\\_ and Iterable ABC\r\n    - A single object can itself iterable by yielding self from \\_\\_iter\\_\\_\r\n  - [Decorator](/src/1_patterns/3_StructuralPatterns/4_Decorator/)\r\n    - A decorator keeps the reference to the decorated object(s)\r\n    - Adds utility attributes and methods to augment the object's features\r\n    - May or may not forward calls to the underlying object\r\n    - Proxying of underlying calls can be done dynamically\r\n    - Python's functional decorators wrap functions; no direct relation to the GoF Decorator Pattern\r\n  - [Façade](/src/1_patterns/3_StructuralPatterns/5_Facade/1_facade.py/)\r\n    - Build a Facade to provide a simplified API over a set of classes\r\n    - May wish to (optionally) expose internals through the facade\r\n    - May allow users to 'escalate' to use more complex API\r\n  - [Flyweight](/src/1_patterns/3_StructuralPatterns/6_Flyweight/)\r\n    - Store common data externally\r\n    - Specify an index or a reference into the external data store\r\n    - Define the idea of 'ranges' on homogeneuous collections and store data related to those ranges\r\n  - [Proxy](/src/1_patterns/3_StructuralPatterns/7_Proxy/)\r\n    - A proxy has the same interface as underlying object\r\n    - To create a proxy, simple replicate the existing interface of an object\r\n    - Add relevant functionality to the redefined member functions\r\n    - Different proxies (communications, logging, caching, etc.) have completely different behaviors\r\n- Behavioral Design Patterns\r\n  - [Chain of Responsibility](/src/1_patterns/4_BehavioralPatterns/1_ChainOfResponsibility/)\r\n    - Chain of responsibility can be implemented as a chain of references or\r\n      a centralized construct\r\n    - Enlist objects in the chain, possibly controlling their order\r\n    - Object removal from chain (e.g., \\_\\_exit\\_\\_)\r\n  - [Command](/src/1_patterns/4_BehavioralPatterns/2_Command/)\r\n    - Encapsulate all details of an operation in a separate object\r\n    - Define instruction for applything the command (either in the command itself, or elsewhere)\r\n    - Optionally define instructions for undoing the command\r\n    - Can create composite commands (a.k.a. macros)\r\n  - [Interpreter](/src/1_patterns/4_BehavioralPatterns/3_Interpreter/)\r\n    - Barring simple cases, an interpreter acts in two stages\r\n    - Lexing turns text into a set of tokens\r\n    - Parsing tokens into meaningful construct\r\n  - [Iterator](/src/1_patterns/4_BehavioralPatterns/4_Iterator/)\r\n    - An iterator specified how you can traverse an object\r\n    - Stateful iterators cannot be recursive\r\n    - yield allows for much more succinct iteration\r\n  - [Mediator](/src/1_patterns/4_BehavioralPatterns/5_Mediator/)\r\n    - Create the mediator and have each object in the system refer to it\r\n      - E.g., in a property\r\n    - Mediator engages in bidirectional communication with its connected components\r\n    - Mediator has functions the components can call\r\n    - Components have functions the mediator can call\r\n    - Event processing (e.g., Rx) libraries make communication easier to implement\r\n  - [Memento](/src/1_patterns/4_BehavioralPatterns/6_Memento/)\r\n    - Mementos are used to roll back states arbitrarily\r\n    - A memento is simply a token/handle class with typically no function of its own\r\n    - A memento is not required to expose directly the state(s) to which it reverts the system\r\n    - Can be used to implement undo/redo\r\n  - [Observer](/src/1_patterns/4_BehavioralPatterns/7_Observer/)\r\n    - Observer is an intrusive approach: an observable must provide an event to subscribe to\r\n    - Subsciption and unsubscription with additional/removal of items in list\r\n    - Property notifications are easy: dependent property notifications are tricky\r\n  - [State](/src/1_patterns/4_BehavioralPatterns/8_State/)\r\n    - Given sufficient complexity, it pays to formally define possible states and events/triggers\r\n    - Can define\r\n      - State entry/exit behaviors\r\n      - Action when a particular event causes a transition\r\n      - Guard conditions enabling/disabling a transition\r\n      - Default action when no transitions are found for an event\r\n  - [Strategy](/src/1_patterns/4_BehavioralPatterns/9_Strategy/1_strategy.py/)\r\n    - Define an algorithm at a high level\r\n    - Define the interface you expect each strategy to follow\r\n    - Provide for dynamic composition of strategies in the resulting object\r\n  - [Template](/src/1_patterns/4_BehavioralPatterns/10_Template/1_template_method.py/)\r\n    - Define an algorithm at a high level in parent class\r\n    - Define constituent parts as abstract methods/properties\r\n    - Inherit the algorthm class, providing the necessary ovverides\r\n  - [Visitor](/src/1_patterns/4_BehavioralPatterns/11_Visitor/)\r\n    - OOP double-dispatch approach is not necessary in Python\r\n    - Make a visitor, decorating each 'overload' with @visitor\r\n    - Call visit() and the entire structure gets traversed\r\n\r\n\r\n## My TOP #11 Methods of Patterns\r\n\r\n|  No |                                                  Name                                                 |                                                           Exercise                                                           |                                                        Test                                                        |                                                                                                                  Description                                                                                                                 |\r\n|:---:|:-----------------------------------------------------------------------------------------------------:|:----------------------------------------------------------------------------------------------------------------------------:|:------------------------------------------------------------------------------------------------------------------:|:--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------:|\r\n|  1. | [ Adapter](/src/1_patterns/3_StructuralPatterns/1_Adapter/)                                           | [ Text and Exercise for Adapter](/src/2_exercises/2_StructuralPatterns/1_Adapter/)                                           | [Test Adapter](/tests/2_StructuralPatterns/1_Adapter/test_adapter.py/)                                             | Allows objects with incompatible interfaces to collaborate.                                                                                                                                                                                  |\r\n|  2. | [ Builder](/src/1_patterns/2_CreationalPatterns/1_Builder/)                                           | [ Text and Exercise for Builder](/src/2_exercises/1_CreationalPatterns/1_Builder/)                                           | [Test Builder](/tests/1_CreationalPatterns/1_Builder/test_builder.py/)                                             | Lets you construct complex objects step by step. The pattern allows you to produce different types and representations of an object using the same construction code.                                                                        |\r\n|  3. | [ Command](/src/1_patterns/4_BehavioralPatterns/2_Command/)                                           | [ Text and Exercise for Command](/src/2_exercises/3_BehavioralPatterns/2_Command/)                                           | [Test Command](/tests/3_BehavioralPatterns/2_Command/test_command.py/)                                             | Turns a request into a stand-alone object that contains all information about the request. This transformation lets you parameterize methods with different requests, delay or queue a request's execution, and support undoable operations. |\r\n|  4. | [ Decorator](/src/1_patterns/3_StructuralPatterns/4_Decorator/)                                       | [ Text and Exercise for Decorator](/src/2_exercises/2_StructuralPatterns/4_Decorator/)                                       | [Test Decorator](tests/2_StructuralPatterns/4_Decorator/test_decorator.py/)                                        | Lets you attach new behaviors to objects by placing these objects inside special wrapper objects that contain the behaviors.                                                                                                                 |\r\n|  5. | [ Factories (Factory Method and Abstract Factory)](/src/1_patterns/2_CreationalPatterns/2_Factories/) | [ Text and Exercise for Factories (Factory Method and Abstract Factory)](/src/2_exercises/1_CreationalPatterns/2_Factories/) | [Test Factories (Factory Method and Abstract Factory)](/tests/1_CreationalPatterns/2_Factories/test_factories.py/) | Provides an interface for creating objects in a superclass, but allows subclasses to alter the type of objects that will be created. Abstract - Lets you produce families of related objects without specifying their concrete classes.      |\r\n|  6. | [ Iterator](/src/1_patterns/4_BehavioralPatterns/4_Iterator/)                                         | [ Text and Exercise for Iterator](/src/2_exercises/3_BehavioralPatterns/4_Iterator/)                                         | [Test Iterator](/tests/3_BehavioralPatterns/4_Iterator/test_iterator.py/)                                          | Lets you traverse elements of a collection without exposing its underlying representation (list, stack, tree, etc.).                                                                                                                         |\r\n|  7. | [ Observer](/src/1_patterns/4_BehavioralPatterns/7_Observer/)                                         | [ Text and Exercise for Observer](/src/2_exercises/3_BehavioralPatterns/7_Observer/)                                         | [Test Observer](/tests/3_BehavioralPatterns/7_Observer/test_observer.py/)                                          | Lets you define a subscription mechanism to notify multiple objects about any events that happen to the object they're observing.                                                                                                            |\r\n|  8. | [ Prototype](/src/1_patterns/2_CreationalPatterns/3_Prototype/)                                       | [ Textand Exercise for Prototype](/src/2_exercises/1_CreationalPatterns/3_Prototype/)                                        | [Test Prototype](/tests/1_CreationalPatterns/3_Prototype/test_prototype.py/)                                       | Lets you copy existing objects without making your code dependent on their classes.                                                                                                                                                          |\r\n|  9. | [ Singleton](/src/1_patterns/2_CreationalPatterns/4_Singleton/)                                       | [ Textand Exercise for Singleton](/src/2_exercises/1_CreationalPatterns/4_Singleton/)                                        | [Test Singleton](/tests/1_CreationalPatterns/4_Singleton/test_singleton.py/)                                       | Lets you ensure that a class has only one instance, while providing a global access point to this instance.                                                                                                                                  |\r\n| 10. | [ Strategy](/src/1_patterns/4_BehavioralPatterns/9_Strategy/1_strategy.py/)                           | [ Text and Exercise for Strategy](/src/2_exercises/3_BehavioralPatterns/9_Strategy/)                                         | [Test Strategy](tests/3_BehavioralPatterns/9_Strategy/test_strategy.py/)                                           | Lets you define a family of algorithms, put each of them into a separate class, and make their objects interchangeable.                                                                                                                      |\r\n| 11. | [ Template](/src/1_patterns/4_BehavioralPatterns/10_Template/1_template_method.py/)                   | [ Text and Exercise for Template](/src/2_exercises/3_BehavioralPatterns/10_Template/)                                        | [Test Template](/tests/3_BehavioralPatterns/10_Template/test_template_method.py/)                                  | Defines the skeleton of an algorithm in the superclass but lets subclasses override specific steps of the algorithm without changing its structure.                                                                                          |\r\n\r\n## Awknowledgements\r\n\r\n- Course work and notes from Udemy course by Dmitri Nesteruk.\r\n\r\n## Author\r\n\r\n- **MT** - [milovantomasevic.com](https://milovantomasevic.com)\r\n\r\n- Certificate of Completion – Udemy - [See credential](https://www.udemy.com/certificate/UC-c9139435-41e7-4038-aa8b-1a2573b5de98/)\r\n\r\n![Certificate of Completion – Udemy](/cert/cert.jpg)\r\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmilovantomasevic%2Fpython-design-patterns","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmilovantomasevic%2Fpython-design-patterns","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmilovantomasevic%2Fpython-design-patterns/lists"}