├── LICENSE ├── README.md ├── abstract-factory ├── AbstractFactory.py └── README.md ├── adapter ├── Adapter.py └── README.md ├── bridge ├── Bridge.py └── README.md ├── builder ├── Builder.py └── README.md ├── chain-of-responsibility ├── ChainOfResponsibility.py └── README.md ├── command ├── Command.py └── README.md ├── composite ├── Composite.py └── README.md ├── decorator ├── Decorator.py └── README.md ├── facade ├── Facade.py └── README.md ├── factory-method ├── FactoryMethod.py └── README.md ├── flyweight ├── Flyweight.py └── README.md ├── interpreter ├── Interpreter.py └── README.md ├── iterator ├── Iterator.py └── README.md ├── mediator ├── Mediator.py └── README.md ├── memento ├── Memento.py └── README.md ├── observer ├── Observer.py └── README.md ├── prototype ├── Prototype.py └── README.md ├── proxy ├── Proxy.py └── README.md ├── singleton ├── README.md └── Singleton.py ├── state ├── README.md └── State.py ├── strategy ├── README.txt └── Strategy.py ├── template-method ├── README.txt └── TemplateMethod.py └── visitor ├── README.md └── Visitor.py /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License 2 | 3 | Copyright (c) 2016 Jakub Vojvoda 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 13 | all 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 21 | THE SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Python Design Patterns 2 | 3 | Software design patterns are general reusable solutions to problems which occur 4 | over and over again in object-oriented design enviroment. It is not a finished 5 | design that can be transformed into source code directly, but it is template how 6 | to solve the problem. We can classify them by purpose into creational (abstract 7 | the instantiation process), structure (how classes and objects are composed to form 8 | larger structures) and behavioral patterns (the assignment of responsibilities between 9 | objects). 10 | 11 | #### Creational Patterns 12 | - [Abstract Factory], families of product objects 13 | - [Builder], how a composite object gets created 14 | - [Factory Method], subclass of object that is instantiated 15 | - [Prototype], class of object that is instantiated 16 | - [Singleton], the sole instance of a class 17 | #### Structural Patterns 18 | - [Adapter], interface to an object 19 | - [Bridge], implementation of an object 20 | - [Composite], structure and composition of an object 21 | - [Decorator], responsibilities of an object without subclassing 22 | - [Façade], interface to a subsystem 23 | - [Flyweight], storage costs of objects 24 | - [Proxy], how an object is accessed (its location) 25 | #### Behavioral Patterns 26 | - [Chain of Responsibility], object that can fulfill a request 27 | - [Command], when and how a request is fulfilled 28 | - [Interpreter], grammar and interpretation of a language 29 | - [Iterator], how an aggregate's elements are accessed 30 | - [Mediator], how and which objects interact with each other 31 | - [Memento], what private information is stored outside an object, and when 32 | - [Observer], how the dependent objects stay up to date 33 | - [State], states of an object 34 | - [Strategy], an algorithm 35 | - [Template Method], steps of an algorithm 36 | - [Visitor], operations that can be applied to objects without changing their classes 37 | 38 | ### Other Languages 39 | In my repository you can find implementation of desgin patterns also in languages as 40 | 41 | * [Design Patterns in C++] 42 | * [Design Patterns in Java] 43 | * [Design Patterns in Python] 44 | 45 | ### References 46 | Design patterns in this repository are based on 47 | 48 | * [Design Patterns by The "Gang of Four"] 49 | * [Head First: Design Patterns] 50 | * [Wikipedia] 51 | 52 | [Design Patterns in C++]: https://github.com/JakubVojvoda/design-patterns-cpp 53 | [Design Patterns in Java]: https://github.com/JakubVojvoda/design-patterns-java 54 | [Design Patterns in Python]: https://github.com/JakubVojvoda/design-patterns-python 55 | 56 | [Design Patterns by The "Gang of Four"]: https://en.wikipedia.org/wiki/Design_Patterns 57 | [Head First: Design Patterns]: http://www.headfirstlabs.com/books/hfdp/ 58 | [Wikipedia]: https://en.wikipedia.org/wiki/Software_design_pattern 59 | 60 | [Abstract Factory]: https://github.com/JakubVojvoda/design-patterns-python/tree/master/abstract-factory 61 | [Builder]: https://github.com/JakubVojvoda/design-patterns-python/tree/master/builder 62 | [Factory Method]: https://github.com/JakubVojvoda/design-patterns-python/tree/master/factory-method 63 | [Prototype]: https://github.com/JakubVojvoda/design-patterns-python/tree/master/prototype 64 | [Singleton]: https://github.com/JakubVojvoda/design-patterns-python/tree/master/singleton 65 | [Adapter]: https://github.com/JakubVojvoda/design-patterns-python/tree/master/adapter 66 | [Bridge]: https://github.com/JakubVojvoda/design-patterns-python/tree/master/bridge 67 | [Composite]: https://github.com/JakubVojvoda/design-patterns-python/tree/master/composite 68 | [Decorator]: https://github.com/JakubVojvoda/design-patterns-python/tree/master/decorator 69 | [Façade]: https://github.com/JakubVojvoda/design-patterns-python/tree/master/facade 70 | [Flyweight]: https://github.com/JakubVojvoda/design-patterns-python/tree/master/flyweight 71 | [Proxy]: https://github.com/JakubVojvoda/design-patterns-python/tree/master/proxy 72 | [Chain of Responsibility]: https://github.com/JakubVojvoda/design-patterns-python/tree/master/chain-of-responsibility 73 | [Command]: https://github.com/JakubVojvoda/design-patterns-python/tree/master/command 74 | [Interpreter]: https://github.com/JakubVojvoda/design-patterns-python/tree/master/interpreter 75 | [Iterator]: https://github.com/JakubVojvoda/design-patterns-python/tree/master/iterator 76 | [Mediator]: https://github.com/JakubVojvoda/design-patterns-python/tree/master/mediator 77 | [Memento]: https://github.com/JakubVojvoda/design-patterns-python/tree/master/memento 78 | [Observer]: https://github.com/JakubVojvoda/design-patterns-python/tree/master/observer 79 | [State]: https://github.com/JakubVojvoda/design-patterns-python/tree/master/state 80 | [Strategy]: https://github.com/JakubVojvoda/design-patterns-python/tree/master/strategy 81 | [Template Method]: https://github.com/JakubVojvoda/design-patterns-python/tree/master/template-method 82 | [Visitor]: https://github.com/JakubVojvoda/design-patterns-python/tree/master/visitor 83 | -------------------------------------------------------------------------------- /abstract-factory/AbstractFactory.py: -------------------------------------------------------------------------------- 1 | # 2 | # Python Design Patterns: Abstract Factory 3 | # Author: Jakub Vojvoda [github.com/JakubVojvoda] 4 | # 2016 5 | # 6 | # Source code is licensed under MIT License 7 | # (for more details see LICENSE) 8 | # 9 | 10 | import sys 11 | 12 | # 13 | # Product A 14 | # products implement the same interface so that the classes can refer 15 | # to the interface not the concrete product 16 | # 17 | class ProductA: 18 | def getName(self): 19 | pass 20 | 21 | # 22 | # ConcreteProductAX and ConcreteProductAY 23 | # define objects to be created by concrete factory 24 | # 25 | class ConcreteProductAX(ProductA): 26 | def getName(self): 27 | return "A-X" 28 | 29 | class ConcreteProductAY(ProductA): 30 | def getName(self): 31 | return "A-Y" 32 | 33 | # 34 | # Product B 35 | # same as Product A, Product B declares interface for concrete products 36 | # where each can produce an entire set of products 37 | # 38 | class ProductB: 39 | def getName(self): 40 | pass 41 | 42 | # 43 | # ConcreteProductBX and ConcreteProductBY 44 | # same as previous concrete product classes 45 | # 46 | class ConcreteProductBX(ProductB): 47 | def getName(self): 48 | return "B-X" 49 | 50 | class ConcreteProductBY(ProductB): 51 | def getName(self): 52 | return "B-Y" 53 | 54 | # 55 | # Abstract Factory 56 | # provides an interface for creating a family of products 57 | # 58 | class AbstractFactory: 59 | def createProductA(self): 60 | pass 61 | 62 | def createProductB(self): 63 | pass 64 | 65 | # 66 | # Concrete Factories 67 | # each concrete factory create a family of products and 68 | # client uses one of these factories 69 | # 70 | class ConcreteFactoryX(AbstractFactory): 71 | def createProductA(self): 72 | return ConcreteProductAX() 73 | 74 | def createProductB(self): 75 | return ConcreteProductBX() 76 | 77 | class ConcreteFactoryY(AbstractFactory): 78 | def createProductA(self): 79 | return ConcreteProductAY() 80 | 81 | def createProductB(self): 82 | return ConcreteProductBY() 83 | 84 | 85 | if __name__ == "__main__": 86 | factoryX = ConcreteFactoryX() 87 | factoryY = ConcreteFactoryY() 88 | 89 | p1 = factoryX.createProductA() 90 | print("Product: " + p1.getName()) 91 | 92 | p2 = factoryY.createProductA() 93 | print("Product: " + p2.getName()) 94 | 95 | 96 | 97 | -------------------------------------------------------------------------------- /abstract-factory/README.md: -------------------------------------------------------------------------------- 1 | ## Abstract Factory 2 | 3 | Abstract factory pattern has creational purpose and provides an interface for 4 | creating families of related or dependent objects without specifying their 5 | concrete classes. Pattern applies to object and deal with object relationships, 6 | which are more dynamic. In contrast to Factory Method, Abstract Factory pattern 7 | produces family of types that are related, ie. it has more than one method of 8 | types it produces. 9 | 10 | 11 | ### When to use 12 | 13 | * a system should be independent of how its products are created, composed, and represented 14 | * a system should be configured with one of multiple families of products 15 | * a family of related product objects is designed to be used together 16 | * you want to provide a class library of products, and you want to reveal just their interfaces, not their implementations -------------------------------------------------------------------------------- /adapter/Adapter.py: -------------------------------------------------------------------------------- 1 | # 2 | # Python Design Patterns: Adapter 3 | # Author: Jakub Vojvoda [github.com/JakubVojvoda] 4 | # 2016 5 | # 6 | # Source code is licensed under MIT License 7 | # (for more details see LICENSE) 8 | # 9 | 10 | import sys 11 | 12 | # 13 | # Target 14 | # defines specific interface that Client uses 15 | # 16 | class Target: 17 | def request(self): 18 | pass 19 | 20 | # 21 | # Adaptee 22 | # all requests get delegated to the Adaptee which defines 23 | # an existing interface that needs adapting 24 | # 25 | class Adaptee: 26 | def specificRequest(self): 27 | print("Specific request") 28 | 29 | # 30 | # Adapter 31 | # implements the Target interface and lets the Adaptee respond 32 | # to request on a Target by extending both classes 33 | # ie adapts the interface of Adaptee to the Target interface 34 | # 35 | class Adapter(Target, Adaptee): 36 | def __init__(self): 37 | Adaptee.__init__(self) 38 | Target.__init__(self) 39 | 40 | def request(self): 41 | return self.specificRequest() 42 | 43 | 44 | if __name__ == "__main__": 45 | t = Adapter() 46 | t.request() 47 | -------------------------------------------------------------------------------- /adapter/README.md: -------------------------------------------------------------------------------- 1 | ## Adapter 2 | 3 | Convert the interface of a class into another interface the clients expect. 4 | Adapter lets classes work together that couldn't otherwise because of 5 | incompatible interfaces, ie. allows to use a client with an incompatible 6 | interface by an Adapter that does the conversion. Adapter has structural purpose 7 | and can be applied on classes and also on object. A class adapter uses multiple 8 | inheritance to adapt one interface to another and the object adapter uses object 9 | composition to combine classes with different interfaces. 10 | 11 | ### When to use 12 | 13 | * you want to use an existing class, and its interface does not match the one you need 14 | * you want to create a reusable class that cooperates with classes that don't necessarily have compatible interfaces 15 | 16 | -------------------------------------------------------------------------------- /bridge/Bridge.py: -------------------------------------------------------------------------------- 1 | # 2 | # Python Design Patterns: Bridge 3 | # Author: Jakub Vojvoda [github.com/JakubVojvoda] 4 | # 2016 5 | # 6 | # Source code is licensed under MIT License 7 | # (for more details see LICENSE) 8 | # 9 | 10 | import sys 11 | 12 | # 13 | # Implementor 14 | # defines the interface for implementation classes 15 | # 16 | class Implementor: 17 | def action(self): 18 | pass 19 | 20 | # 21 | # Concrete Implementors 22 | # implement the Implementor interface and define concrete implementations 23 | # 24 | class ConcreteImplementorA(Implementor): 25 | def action(self): 26 | print("Concrete Implementor A") 27 | 28 | class ConcreteImplementorB(Implementor): 29 | def action(self): 30 | print("Concrete Implementor B") 31 | 32 | # 33 | # Bridge 34 | # decouple an abstraction from its implementation 35 | # 36 | class Bridge: 37 | def __init__(self, implementation): 38 | self._implementor = implementation 39 | 40 | def operation(self): 41 | self._implementor.action() 42 | 43 | 44 | if __name__ == "__main__": 45 | bridge = Bridge(ConcreteImplementorA()) 46 | bridge.operation() 47 | 48 | bridge = Bridge(ConcreteImplementorB()) 49 | bridge.operation() 50 | -------------------------------------------------------------------------------- /bridge/README.md: -------------------------------------------------------------------------------- 1 | ## Bridge 2 | 3 | Decouple an abstraction from its implementation so that the two can vary independently. 4 | Bridge pattern has structural purpose and applies to objects, so it deals with the composition of objects. 5 | 6 | ### When to use 7 | 8 | * you want to avoid a permanent binding between an abstraction and its implementation 9 | * both the abstractions and their implementations should be extensible by subclassing 10 | * changes in the implementation of an abstraction should have no impact on clients 11 | * you want to hide the implementation of an abstraction completely from clients 12 | -------------------------------------------------------------------------------- /builder/Builder.py: -------------------------------------------------------------------------------- 1 | # 2 | # Python Design Patterns: Builder 3 | # Author: Jakub Vojvoda [github.com/JakubVojvoda] 4 | # 2016 5 | # 6 | # Source code is licensed under MIT License 7 | # (for more details see LICENSE) 8 | # 9 | 10 | import sys 11 | 12 | # 13 | # Product 14 | # the final object that will be created using Builder 15 | # 16 | class Product: 17 | def __init__(self): 18 | self._partA = "" 19 | self._partB = "" 20 | self._partC = "" 21 | 22 | def makeA(self, part): 23 | self._partA = part 24 | 25 | def makeB(self, part): 26 | self._partB = part 27 | 28 | def makeC(self, part): 29 | self._partC = part 30 | 31 | def get(self): 32 | return self._partA +" "+ self._partB +" "+ self._partC 33 | 34 | # 35 | # Builder 36 | # abstract interface for creating products 37 | # 38 | class Builder: 39 | def __init__(self): 40 | self._product = Product() 41 | 42 | def get(self): 43 | return self._product 44 | 45 | def buildPartA(): 46 | pass 47 | 48 | def buildPartB(): 49 | pass 50 | 51 | def buildPartC(): 52 | pass 53 | 54 | # 55 | # Concrete Builders 56 | # create real products and stores them in the composite structure 57 | # 58 | class ConcreteBuilderX(Builder): 59 | def __init__(self): 60 | Builder.__init__(self) 61 | 62 | def buildPartA(self): 63 | self._product.makeA("A-X") 64 | 65 | def buildPartB(self): 66 | self._product.makeB("B-X") 67 | 68 | def buildPartC(self): 69 | self._product.makeC("C-X") 70 | 71 | class ConcreteBuilderY(Builder): 72 | def __init__(self): 73 | Builder.__init__(self) 74 | 75 | def buildPartA(self): 76 | self._product.makeA("A-Y") 77 | 78 | def buildPartB(self): 79 | self._product.makeB("B-Y") 80 | 81 | def buildPartC(self): 82 | self._product.makeC("C-Y") 83 | 84 | # 85 | # Director 86 | # responsible for managing the correct sequence of object creation 87 | # 88 | class Director: 89 | def __init__(self): 90 | self._builder = None 91 | 92 | def set(self, builder): 93 | self._builder = builder 94 | 95 | def get(self): 96 | return self._builder.get() 97 | 98 | def construct(self): 99 | self._builder.buildPartA() 100 | self._builder.buildPartB() 101 | self._builder.buildPartC() 102 | 103 | 104 | if __name__ == "__main__": 105 | builderX = ConcreteBuilderX() 106 | builderY = ConcreteBuilderY() 107 | 108 | director = Director() 109 | director.set(builderX) 110 | director.construct() 111 | 112 | product1 = director.get() 113 | print("1st product parts: " + product1.get()) 114 | 115 | director.set(builderY) 116 | director.construct() 117 | 118 | product2 = director.get() 119 | print("2nd product parts: " + product2.get()) 120 | -------------------------------------------------------------------------------- /builder/README.md: -------------------------------------------------------------------------------- 1 | ## Builder 2 | 3 | Builder pattern has creational purpose and separates the construction of a complex object 4 | from its representation so that the same construction process can create different 5 | representations. It is object pattern, ie. relationships can be changed at run-time 6 | and are more dynamic. Often is used for building composite structures but constructing 7 | objects requires more domain knowledge of the client than using a Factory. 8 | 9 | ### When to use 10 | 11 | * the algorithm for creating a object should be independent of the parts and how they're assembled 12 | * the construction process must allow different representations for the object that's constructed -------------------------------------------------------------------------------- /chain-of-responsibility/ChainOfResponsibility.py: -------------------------------------------------------------------------------- 1 | # 2 | # Python Design Patterns: Chain of Responsibility 3 | # Author: Jakub Vojvoda [github.com/JakubVojvoda] 4 | # 2016 5 | # 6 | # Source code is licensed under MIT License 7 | # (for more details see LICENSE) 8 | # 9 | 10 | import sys 11 | 12 | # 13 | # Handler 14 | # defines an interface for handling requests and 15 | # optionally implements the successor link 16 | # 17 | class Handler: 18 | def __init__(self): 19 | self._successor = None 20 | 21 | def setHandler(self, successor): 22 | self._successor = successor 23 | 24 | def handleRequest(self): 25 | if (self._successor is not None): 26 | self._successor.handleRequest(); 27 | 28 | # 29 | # Concrete Handlers 30 | # handle requests they are responsible for 31 | # 32 | class ConcreteHandler1(Handler): 33 | def __init__(self): 34 | Handler.__init__(self) 35 | self._can_handle = False 36 | 37 | def handleRequest(self): 38 | if (self._can_handle): 39 | print( "Handled by Concrete Handler 1.") 40 | else: 41 | print("Cannot be handled by Handler 1.") 42 | super().handleRequest() 43 | 44 | class ConcreteHandler2(Handler): 45 | def __init__(self): 46 | Handler.__init__(self) 47 | self._can_handle = True 48 | 49 | def handleRequest(self): 50 | if (self._can_handle): 51 | print( "Handled by Concrete Handler 2.") 52 | else: 53 | print("Cannot be handled by Handler 2.") 54 | super().handleRequest() 55 | 56 | 57 | if __name__ == "__main__": 58 | handler1 = ConcreteHandler1() 59 | handler2 = ConcreteHandler2() 60 | 61 | handler1.setHandler(handler2) 62 | handler1.handleRequest() 63 | -------------------------------------------------------------------------------- /chain-of-responsibility/README.md: -------------------------------------------------------------------------------- 1 | ## Chain of Responsibility 2 | 3 | Chain of Responsibility pattern avoids coupling the sender of a request to its receiver 4 | by giving more than one object a chance to handle the request. The pattern chains 5 | the receiving objects and passes the request along the chain until an object handles it. 6 | It has a behavioral purpose and deals with relationships between objects. 7 | 8 | ### When to use 9 | 10 | * more than one object may handle a request, and the handler should be ascertained automatically 11 | * you want to issue a request to one of several objects without specifying the receiver explicitly 12 | * the set of objects that can handle a request should be specified dynamically -------------------------------------------------------------------------------- /command/Command.py: -------------------------------------------------------------------------------- 1 | # 2 | # Python Design Patterns: Command 3 | # Author: Jakub Vojvoda [github.com/JakubVojvoda] 4 | # 2016 5 | # 6 | # Source code is licensed under MIT License 7 | # (for more details see LICENSE) 8 | # 9 | 10 | import sys 11 | 12 | # 13 | # Receiver 14 | # knows how to perform the operations associated 15 | # with carrying out a request 16 | # 17 | class Receiver: 18 | def action(self): 19 | print("Receiver: execute action.") 20 | 21 | # 22 | # Command 23 | # declares an interface for all commands 24 | # 25 | class Command: 26 | def execute(self): 27 | pass 28 | 29 | # 30 | # Concrete Command 31 | # implements execute by invoking the corresponding 32 | # operation(s) on Receiver 33 | # 34 | class ConcreteCommand(Command): 35 | def __init__(self, receiver): 36 | self._receiver = receiver 37 | 38 | def execute(self): 39 | self._receiver.action() 40 | 41 | # 42 | # Invoker 43 | # asks the command to carry out the request 44 | # 45 | class Invoker: 46 | def __init__(self): 47 | self._command = None 48 | 49 | def set(self, command): 50 | self._command = command 51 | 52 | def confirm(self): 53 | if (self._command is not None): 54 | self._command.execute() 55 | 56 | 57 | if __name__ == "__main__": 58 | receiver = Receiver() 59 | command = ConcreteCommand(receiver) 60 | 61 | invoker = Invoker() 62 | invoker.set(command) 63 | invoker.confirm() 64 | -------------------------------------------------------------------------------- /command/README.md: -------------------------------------------------------------------------------- 1 | ## Command 2 | 3 | Command pattern encapsulates a request as an object, thereby letting you parameterize 4 | clients with different requests, queue or log requests, and supports undoable 5 | operations. The pattern has a behavioral purpose and deals with relationships between objects. 6 | 7 | ### When to use 8 | 9 | * want to parameterize objects by an action to perform 10 | * want to specify, queue, and execute requests at different times 11 | * support undo 12 | * support logging changes so that they can be reapplied in case of a system crash 13 | * structure a system around high-level operations built on primitives operations 14 | -------------------------------------------------------------------------------- /composite/Composite.py: -------------------------------------------------------------------------------- 1 | # 2 | # Python Design Patterns: Composite 3 | # Author: Jakub Vojvoda [github.com/JakubVojvoda] 4 | # 2016 5 | # 6 | # Source code is licensed under MIT License 7 | # (for more details see LICENSE) 8 | # 9 | 10 | import sys 11 | 12 | # 13 | # Component 14 | # defines an interface for all objects in the composition 15 | # both the composite and the leaf nodes 16 | # 17 | class Component: 18 | def getChild(self, index): 19 | pass 20 | 21 | def add(self, component): 22 | pass 23 | 24 | def remove(self, index): 25 | pass 26 | 27 | def operation(self): 28 | pass 29 | 30 | # 31 | # Composite 32 | # defines behavior of the components having children 33 | # and store child components 34 | # 35 | class Composite(Component): 36 | def __init__(self): 37 | Component.__init__(self) 38 | self._children = [] 39 | 40 | def getChild(self, index): 41 | return self._children[index] 42 | 43 | def add(self, component): 44 | self._children.append(component) 45 | 46 | def remove(self, index): 47 | self._children.remove(index) 48 | 49 | def operation(self): 50 | for i in range(len(self._children)): 51 | self._children[i].operation() 52 | 53 | # 54 | # Leaf 55 | # defines the behavior for the elements in the composition, 56 | # it has no children 57 | # 58 | class Leaf(Component): 59 | def __init__(self, index): 60 | Component.__init__(self) 61 | self._idx = index 62 | 63 | def operation(self): 64 | print("Leaf " + str(self._idx) + " operation.") 65 | 66 | 67 | if __name__ == "__main__": 68 | composite = Composite() 69 | 70 | for i in range(5): 71 | composite.add(Leaf(i)) 72 | 73 | composite.operation() -------------------------------------------------------------------------------- /composite/README.md: -------------------------------------------------------------------------------- 1 | ## Composite 2 | 3 | Compose objects into tree structures to represent part-whole hierarchies. 4 | Composite lets clients treat individual objects and compositions of objects uniformly. 5 | The pattern has structural purpose and applies to objects. 6 | 7 | ### When to use 8 | 9 | * you want to represent part-whole hierarchies of objects 10 | * you want clients to be able to ignore the difference between compositions of objects and individual objects -------------------------------------------------------------------------------- /decorator/Decorator.py: -------------------------------------------------------------------------------- 1 | # 2 | # Python Design Patterns: Decorator 3 | # Author: Jakub Vojvoda [github.com/JakubVojvoda] 4 | # 2016 5 | # 6 | # Source code is licensed under MIT License 7 | # (for more details see LICENSE) 8 | # 9 | 10 | import sys 11 | 12 | # 13 | # Component 14 | # defines an interface for objects that can have responsibilities 15 | # added to them dynamically 16 | # 17 | class Component: 18 | def operation(self): 19 | pass 20 | 21 | # 22 | # Concrete Component 23 | # defines an object to which additional responsibilities 24 | # can be attached 25 | # 26 | class ConcreteComponent(Component): 27 | def __init__(self): 28 | Component.__init__(self) 29 | 30 | def operation(self): 31 | print("Concrete Component operation") 32 | 33 | # 34 | # Decorator 35 | # maintains a reference to a Component object and defines an interface 36 | # that conforms to Component's interface 37 | # 38 | class Decorator(Component): 39 | def __init__(self, component): 40 | Component.__init__(self) 41 | self._component = component 42 | 43 | def operation(self): 44 | self._component.operation() 45 | 46 | # 47 | # Concrete Decorators 48 | # add responsibilities to the component (can extend the state 49 | # of the component) 50 | # 51 | class ConcreteDecoratorA(Decorator): 52 | def __init__(self, component): 53 | super().__init__(component) 54 | 55 | def operation(self): 56 | super().operation() 57 | print("Decorator A") 58 | 59 | class ConcreteDecoratorB(Decorator): 60 | def __init__(self, component): 61 | super().__init__(component) 62 | 63 | def operation(self): 64 | super().operation() 65 | print("Decorator B") 66 | 67 | 68 | if __name__ == "__main__": 69 | component = ConcreteDecoratorA( 70 | ConcreteDecoratorB( ConcreteComponent() ) ) 71 | 72 | component.operation() 73 | -------------------------------------------------------------------------------- /decorator/README.md: -------------------------------------------------------------------------------- 1 | ## Decorator 2 | 3 | Attach additional responsibilities to an object dynamically. Decorators 4 | provide a flexible alternative to subclassing for extending functionality. 5 | The pattern has structural purpose and applies to objects. 6 | 7 | ### When to use 8 | 9 | * to add responsibilities to individual objects dynamically and transparently, that is, without affecting other objects 10 | * for responsibilities that can be withdrawn 11 | * when extension by subclassing is impractical -------------------------------------------------------------------------------- /facade/Facade.py: -------------------------------------------------------------------------------- 1 | # 2 | # Python Design Patterns: Facade 3 | # Author: Jakub Vojvoda [github.com/JakubVojvoda] 4 | # 2016 5 | # 6 | # Source code is licensed under MIT License 7 | # (for more details see LICENSE) 8 | # 9 | 10 | import sys 11 | 12 | # 13 | # Subsystems 14 | # implement more complex subsystem functionality 15 | # and have no knowledge of the facade 16 | # 17 | class SubsystemA: 18 | def suboperation(self): 19 | print("Subsystem A method") 20 | 21 | class SubsystemB: 22 | def suboperation(self): 23 | print("Subsystem B method") 24 | 25 | class SubsystemC: 26 | def suboperation(self): 27 | print("Subsystem C method") 28 | 29 | # 30 | # Facade 31 | # delegates client requests to appropriate subsystem object 32 | # and unified interface that is easier to use 33 | # 34 | class Facade: 35 | def __init__(self): 36 | self._subA = SubsystemA() 37 | self._subB = SubsystemB() 38 | self._subC = SubsystemC() 39 | 40 | def operation1(self): 41 | self._subA.suboperation() 42 | self._subB.suboperation() 43 | 44 | def operation2(self): 45 | self._subC.suboperation() 46 | 47 | 48 | if __name__ == "__main__": 49 | facade = Facade() 50 | facade.operation1() 51 | facade.operation2() -------------------------------------------------------------------------------- /facade/README.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JakubVojvoda/design-patterns-python/eb0bc23ccdbecc6c51043df7917b8a3f7568eb74/facade/README.md -------------------------------------------------------------------------------- /factory-method/FactoryMethod.py: -------------------------------------------------------------------------------- 1 | # 2 | # Python Design Patterns: Factory Method 3 | # Author: Jakub Vojvoda [github.com/JakubVojvoda] 4 | # 2016 5 | # 6 | # Source code is licensed under MIT License 7 | # (for more details see LICENSE) 8 | # 9 | 10 | import sys 11 | 12 | # 13 | # Product 14 | # products implement the same interface so that the classes 15 | # can refer to the interface not the concrete product 16 | # 17 | class Product: 18 | def getName(self): 19 | pass 20 | 21 | # 22 | # Concrete Products 23 | # define product to be created 24 | # 25 | class ConcreteProductA(Product): 26 | def getName(self): 27 | return "type A" 28 | 29 | class ConcreteProductB(Product): 30 | def getName(self): 31 | return "type B" 32 | 33 | # 34 | # Creator 35 | # contains the implementation for all of the methods 36 | # to manipulate products except for the factory method 37 | # 38 | class Creator: 39 | def createProductA(self): 40 | pass 41 | 42 | def createProductB(self): 43 | pass 44 | 45 | # 46 | # Concrete Creator 47 | # implements factory method that is responsible for creating 48 | # one or more concrete products ie. it is class that has 49 | # the knowledge of how to create the products 50 | # 51 | class ConcreteCreator(Creator): 52 | def createProductA(self): 53 | return ConcreteProductA() 54 | 55 | def createProductB(self): 56 | return ConcreteProductB() 57 | 58 | 59 | if __name__ == "__main__": 60 | creator = ConcreteCreator() 61 | 62 | p1 = creator.createProductA() 63 | print("Product: " + p1.getName()) 64 | 65 | p2 = creator.createProductB() 66 | print("Product: " + p2.getName()) 67 | -------------------------------------------------------------------------------- /factory-method/README.md: -------------------------------------------------------------------------------- 1 | ## Factory Method 2 | 3 | Define an interface for creating an object, but let subclasses decide which class to instantiate. 4 | Factory Method lets a class defer instantiation to subclasses. The pattern has creational purpose 5 | and applies to classes where deals with relationships through inheritence ie. they are static-fixed 6 | at compile time. In contrast to Abstract Factory, Factory Method contain method to produce only one 7 | type of product. 8 | 9 | ### When to use 10 | 11 | * a class cant anticipate the class of objects it must create 12 | * a class wants its subclasses to specify the objects it creates 13 | * classes delegate responsibility to one of several helper subclasses, and you want to localize the knowledge of which helper subclass is the delegate -------------------------------------------------------------------------------- /flyweight/Flyweight.py: -------------------------------------------------------------------------------- 1 | # 2 | # Python Design Patterns: Flyweight 3 | # Author: Jakub Vojvoda [github.com/JakubVojvoda] 4 | # 2016 5 | # 6 | # Source code is licensed under MIT License 7 | # (for more details see LICENSE) 8 | # 9 | 10 | import sys 11 | 12 | # 13 | # Flyweight 14 | # declares an interface through which flyweights can receive 15 | # and act on extrinsic state 16 | # 17 | class Flyweight: 18 | def operation(self): 19 | pass 20 | 21 | # 22 | # UnsharedConcreteFlyweight 23 | # not all subclasses need to be shared 24 | # 25 | class UnsharedConcreteFlyweight(Flyweight): 26 | def __init__(self, state): 27 | Flyweight.__init__(self) 28 | self._state = state 29 | 30 | def operation(self): 31 | print("Unshared Flyweight with state " + str(self._state)) 32 | 33 | # 34 | # ConcreteFlyweight 35 | # implements the Flyweight interface and adds storage 36 | # for intrinsic state 37 | # 38 | class ConcreteFlyweight(Flyweight): 39 | def __init__(self, state): 40 | Flyweight.__init__(self) 41 | self._state = state 42 | 43 | def operation(self): 44 | print("Concrete Flyweight with state " + str(self._state)) 45 | 46 | # 47 | # FlyweightFactory 48 | # creates and manages flyweight objects and ensures 49 | # that flyweights are shared properly 50 | # 51 | class FlyweightFactory: 52 | def __init__(self): 53 | self._flies = {} 54 | 55 | def getFlyweight(self, key): 56 | if (self._flies.get(key) is not None): 57 | return self._flies.get(key) 58 | 59 | self._flies[key] = ConcreteFlyweight(key) 60 | return self._flies.get(key) 61 | 62 | 63 | if __name__ == "__main__": 64 | factory = FlyweightFactory() 65 | 66 | factory.getFlyweight(1).operation() 67 | factory.getFlyweight(2).operation() 68 | -------------------------------------------------------------------------------- /flyweight/README.md: -------------------------------------------------------------------------------- 1 | ## Flyweight 2 | 3 | Flyweight pattern has has structural purpose, applies to objects and uses sharing to support 4 | large numbers of fine-grained objects efficiently. The pattern can be used to reduce 5 | memory usage when you need to create a large number of similar objects. 6 | 7 | ### When to use 8 | 9 | * when one instance of a class can be used to provide many "virtual instances" 10 | * when all of the following are true 11 | * an application uses a large number of objects 12 | * storage costs are high because of the sheer quantity of objects 13 | * most object state can be made extrinsic 14 | * many groups of objects may be replaced by relatively few shared objects once extrinsic state is removed 15 | * the application doesn't depend on object identity -------------------------------------------------------------------------------- /interpreter/Interpreter.py: -------------------------------------------------------------------------------- 1 | # 2 | # Python Design Patterns: Interpreter 3 | # Author: Jakub Vojvoda [github.com/JakubVojvoda] 4 | # 2016 5 | # 6 | # Source code is licensed under MIT License 7 | # (for more details see LICENSE) 8 | # 9 | 10 | import sys 11 | 12 | # 13 | # Context 14 | # contains information that's global to the interpreter 15 | # 16 | class Context: 17 | def __init__(self): 18 | self._vars = {} 19 | 20 | def set(self, var, value): 21 | self._vars[var] = value 22 | 23 | def get(self, exp): 24 | return self._vars[exp] 25 | 26 | # 27 | # Abstract Expression 28 | # declares an abstract Interpret operation that is common to all nodes 29 | # in the abstract syntax tree 30 | # 31 | class AbstractExpression: 32 | def interpret(self, context): 33 | return False 34 | 35 | # 36 | # Terminal Expression 37 | # implements an Interpret operation associated with terminal symbols 38 | # in the grammar (an instance is required for every terminal symbol 39 | # in a sentence) 40 | # 41 | class TerminalExpression(AbstractExpression): 42 | def __init__(self, value): 43 | AbstractExpression.__init__(self) 44 | self._value = value 45 | 46 | def interpret(self, context): 47 | return context.get(self._value) 48 | 49 | # 50 | # Nonterminal Expression 51 | # implements an Interpret operation for nonterminal symbols 52 | # in the grammar (one such class is required for every rule in the grammar) 53 | # 54 | class NonterminalExpression(AbstractExpression): 55 | def __init__(self, expr_left, expr_right): 56 | self._lop = expr_left 57 | self._rop = expr_right 58 | 59 | def interpret(self, context): 60 | return self._lop.interpret(context) and self._rop.interpret(context) 61 | 62 | 63 | # An example of very simple expression tree 64 | # that corresponds to expression (A AND B) 65 | if __name__ == "__main__": 66 | A = TerminalExpression("A") 67 | B = TerminalExpression("B") 68 | exp = NonterminalExpression(A, B) 69 | 70 | context = Context() 71 | context.set("A", True) 72 | context.set("B", True) 73 | 74 | print(str(context.get("A")) + " AND " + str(context.get("B")), end = "" ) 75 | print(" = " + str(exp.interpret(context))) 76 | 77 | context.set("A", True) 78 | context.set("B", False) 79 | 80 | print(str(context.get("A")) + " AND " + str(context.get("B")), end = "" ) 81 | print(" = " + str(exp.interpret(context))) 82 | -------------------------------------------------------------------------------- /interpreter/README.md: -------------------------------------------------------------------------------- 1 | ## Interpreter 2 | 3 | Given a language, the pattern defines a represention for its grammar along with an 4 | interpreter that uses the representation to interpret sentences in the language. 5 | The Interpreter pattern has behavioral purpose and applies to the classes. 6 | 7 | ### When to use 8 | 9 | * when the grammar is simple (in case of complex grammars, there are better alternatives) 10 | * efficiency is not a critical concern -------------------------------------------------------------------------------- /iterator/Iterator.py: -------------------------------------------------------------------------------- 1 | # 2 | # Python Design Patterns: Iterator 3 | # Author: Jakub Vojvoda [github.com/JakubVojvoda] 4 | # 2016 5 | # 6 | # Source code is licensed under MIT License 7 | # (for more details see LICENSE) 8 | # 9 | 10 | import sys 11 | 12 | # 13 | # Aggregate 14 | # has a collection of objects and implements the method 15 | # that returns an Iterator for its collection 16 | # 17 | class Aggregate: 18 | def __init__(self): 19 | self._list = [] 20 | 21 | def __iter__(self): 22 | return Iterator(self._list) 23 | 24 | def get(self, index): 25 | return self._list[index] 26 | 27 | def set(self, l): 28 | self._list = l 29 | 30 | # 31 | # Iterator 32 | # implements methods for traversing over elements and 33 | # is responsible for managing the current position of the iterator 34 | # 35 | class Iterator: 36 | def __init__(self, aggregate): 37 | self._list = aggregate 38 | self._size = len(aggregate) 39 | self._index = 0 40 | 41 | def __iter__(self): 42 | return self 43 | 44 | def __next__(self): 45 | if self._index < self._size: 46 | pos = self._index 47 | self._index += 1 48 | return aggregate.get(pos) 49 | else: 50 | raise StopIteration() 51 | 52 | 53 | if __name__ == "__main__": 54 | aggregate = Aggregate() 55 | aggregate.set([10,20,30,40,50]) 56 | 57 | for value in list(aggregate): 58 | print("Item value: " + str(value)) 59 | -------------------------------------------------------------------------------- /iterator/README.md: -------------------------------------------------------------------------------- 1 | ## Iterator 2 | 3 | Iterator pattern has behavioral purpose and applies to objects. The pattern provides 4 | a way to access the elements of an aggregate object sequentially without exposing 5 | its underlying representation. 6 | 7 | ### When to use 8 | 9 | * to access an aggregate object's contents without exposing its internal representation 10 | * to support multiple traversals of aggregate objects 11 | * to provide a uniform interface for traversing different aggregate structures 12 | (to support polymorphic iteration) -------------------------------------------------------------------------------- /mediator/Mediator.py: -------------------------------------------------------------------------------- 1 | # 2 | # Python Design Patterns: Mediator 3 | # Author: Jakub Vojvoda [github.com/JakubVojvoda] 4 | # 2016 5 | # 6 | # Source code is licensed under MIT License 7 | # (for more details see LICENSE) 8 | # 9 | 10 | import sys 11 | 12 | # 13 | # Colleague classes 14 | # each colleague communicates with its mediator whenever 15 | # it would have otherwise communicated with another colleague 16 | # 17 | class Colleague: 18 | def __init__(self, mediator, identity): 19 | self._mediator = mediator 20 | self._id = identity 21 | 22 | def getID(self): 23 | return self._id 24 | 25 | def send(self, message): 26 | pass 27 | 28 | def receive(self, message): 29 | pass 30 | 31 | class ConcreteColleague(Colleague): 32 | def __init__(self, mediator, identity): 33 | super().__init__(mediator, identity) 34 | 35 | def send(self, message): 36 | print("Message '" + message + "' sent by Colleague " + str(self._id)) 37 | self._mediator.distribute(self, message) 38 | 39 | def receive(self, message): 40 | print("Message '" + message + "' received by Colleague " + str(self._id)) 41 | 42 | # 43 | # Mediator 44 | # defines an interface for communicating with Colleague objects 45 | # 46 | class Mediator: 47 | def add(self, colleague): 48 | pass 49 | 50 | def distribute(self, sender, message): 51 | pass 52 | 53 | # 54 | # Concrete Mediator 55 | # implements cooperative behavior by coordinating Colleague objects 56 | # and knows its colleagues 57 | # 58 | class ConcreteMediator(Mediator): 59 | def __init__(self): 60 | Mediator.__init__(self) 61 | self._colleagues = [] 62 | 63 | def add(self, colleague): 64 | self._colleagues.append(colleague) 65 | 66 | def distribute(self, sender, message): 67 | for colleague in self._colleagues: 68 | if colleague.getID() != sender.getID(): 69 | colleague.receive(message) 70 | 71 | 72 | if __name__ == "__main__": 73 | mediator = ConcreteMediator() 74 | 75 | c1 = ConcreteColleague(mediator, 1) 76 | c2 = ConcreteColleague(mediator, 2) 77 | c3 = ConcreteColleague(mediator, 3) 78 | 79 | mediator.add(c1) 80 | mediator.add(c2) 81 | mediator.add(c3) 82 | 83 | c1.send("Hi!"); 84 | c3.send("Hello!"); 85 | -------------------------------------------------------------------------------- /mediator/README.md: -------------------------------------------------------------------------------- 1 | ## Mediator 2 | 3 | Mediator pattern has behavioral purpose and applies on objects. 4 | The pattern defines an object that encapsulates how a set of objects interact. 5 | It promotes loose coupling by keeping objects from referring to each 6 | other explicitly, and it lets you vary their interaction independently. 7 | 8 | ### When to use 9 | 10 | * a set of objects communicate in well-defined but complex ways 11 | * reusing an object is difficult because it refers to and communicates with many other objects 12 | * a behavior that's distributed between several classes should be customizable without a lot of subclassing -------------------------------------------------------------------------------- /memento/Memento.py: -------------------------------------------------------------------------------- 1 | # 2 | # Python Design Patterns: Memento 3 | # Author: Jakub Vojvoda [github.com/JakubVojvoda] 4 | # 2016 5 | # 6 | # Source code is licensed under MIT License 7 | # (for more details see LICENSE) 8 | # 9 | 10 | import sys 11 | 12 | # 13 | # Memento 14 | # stores internal state of the Originator object and protects 15 | # against access by objects other than the originator 16 | # 17 | class Memento: 18 | def __init__(self, state): 19 | self._state = state 20 | 21 | def setState(self, state): 22 | self._state = state; 23 | 24 | def getState(self): 25 | return self._state 26 | 27 | # 28 | # Originator 29 | # creates a memento containing a snapshot of its current internal 30 | # state and uses the memento to restore its internal state 31 | # 32 | class Originator: 33 | def __init__(self): 34 | self._state = 0 35 | 36 | def setState(self, state): 37 | print("Set state to " + str(state) + ".") 38 | self._state = state 39 | 40 | def getState(self): 41 | return self._state 42 | 43 | def setMemento(self, memento): 44 | self._state = memento.getState() 45 | 46 | def createMemento(self): 47 | return Memento(self._state) 48 | 49 | # 50 | # CareTaker 51 | # is responsible for the memento's safe keeping 52 | # 53 | class CareTaker: 54 | def __init__(self, originator): 55 | self._originator = originator 56 | self._history = [] 57 | 58 | def save(self): 59 | print("Save state.") 60 | self._history.append(self._originator.createMemento()) 61 | 62 | def undo(self): 63 | print("Undo state.") 64 | self._originator.setMemento(self._history[-1]) 65 | self._history.pop() 66 | 67 | 68 | if __name__ == "__main__": 69 | originator = Originator() 70 | caretaker = CareTaker(originator) 71 | 72 | originator.setState(1) 73 | caretaker.save() 74 | 75 | originator.setState(2) 76 | caretaker.save() 77 | 78 | originator.setState(3) 79 | caretaker.undo() 80 | 81 | print("Actual state is " + str(originator.getState()) + ".") 82 | -------------------------------------------------------------------------------- /memento/README.md: -------------------------------------------------------------------------------- 1 | ## Memento 2 | 3 | Memento without violating encapsulation, captures and externalizes an object's internal 4 | state so that the object can be restored to this state later. The pattern has behavioral 5 | purpose and applies to the objects. 6 | 7 | ### When to use 8 | 9 | * a snapshot of an object's state must be saved so that it can be restored to that state later 10 | * a direct interface to obtaining the state would expose implementation details and break the object's encapsulation -------------------------------------------------------------------------------- /observer/Observer.py: -------------------------------------------------------------------------------- 1 | # 2 | # Python Design Patterns: Observer 3 | # Author: Jakub Vojvoda [github.com/JakubVojvoda] 4 | # 2016 5 | # 6 | # Source code is licensed under MIT License 7 | # (for more details see LICENSE) 8 | # 9 | 10 | import sys 11 | 12 | # 13 | # Observer 14 | # defines an updating interface for objects that should be notified 15 | # of changes in a subject 16 | # 17 | class Observer: 18 | def getState(self): 19 | pass 20 | 21 | def update(self, subject): 22 | pass 23 | 24 | # 25 | # Concrete Observer 26 | # stores state of interest to ConcreteObserver objects and 27 | # sends a notification to its observers when its state changes 28 | # 29 | class ConcreteObserver(Observer): 30 | def __init__(self, state): 31 | Observer.__init__(self) 32 | self._state = state 33 | 34 | def getState(self): 35 | return self._state 36 | 37 | def update(self, subject): 38 | self._state = subject.getState() 39 | print("Observer state updated.") 40 | 41 | # 42 | # Subject 43 | # knows its observers and provides an interface for attaching 44 | # and detaching observers 45 | # 46 | class Subject: 47 | def __init__(self): 48 | self._observers = [] 49 | 50 | def attach(self, observer): 51 | self._observers.append(observer) 52 | 53 | def detach(self, index): 54 | self._observers.remove(index) 55 | 56 | def notify(self): 57 | for observer in self._observers: 58 | observer.update(self) 59 | 60 | def getState(self): 61 | pass 62 | 63 | def setState(self, state): 64 | pass 65 | 66 | # 67 | # Concrete Subject 68 | # stores state that should stay consistent with the subject's 69 | # 70 | class ConcreteSubject(Subject): 71 | def __init__(self): 72 | Subject.__init__(self) 73 | self._state = 0 74 | 75 | def getState(self): 76 | return self._state 77 | 78 | def setState(self, state): 79 | self._state = state 80 | 81 | 82 | if __name__ == "__main__": 83 | observer1 = ConcreteObserver(1) 84 | observer2 = ConcreteObserver(2) 85 | 86 | print("Observer 1 state: " + str(observer1.getState())) 87 | print("Observer 2 state: " + str(observer2.getState())) 88 | 89 | subject = ConcreteSubject() 90 | subject.attach(observer1) 91 | subject.attach(observer2) 92 | 93 | subject.setState(10) 94 | subject.notify() 95 | 96 | print("Observer 1 state: " + str(observer1.getState())) 97 | print("Observer 2 state: " + str(observer2.getState())) 98 | -------------------------------------------------------------------------------- /observer/README.md: -------------------------------------------------------------------------------- 1 | ## Observer 2 | 3 | Observer defines a one-to-many dependency between objects so that when one object 4 | changes state, all its dependents are notified and updated automatically. The pattern 5 | has behavioral purpose and applies to the objects. 6 | 7 | ### When to use 8 | 9 | * when an abstraction has two aspects, one dependent on the other 10 | * when a change to one object requires changing others, and you don't know how many objects need to be changed 11 | * when an object should be able to notify other objects without making assumptions about who these objects are -------------------------------------------------------------------------------- /prototype/Prototype.py: -------------------------------------------------------------------------------- 1 | # 2 | # Python Design Patterns: Prototype 3 | # Author: Jakub Vojvoda [github.com/JakubVojvoda] 4 | # 2016 5 | # 6 | # Source code is licensed under MIT License 7 | # (for more details see LICENSE) 8 | # 9 | 10 | import sys 11 | import copy 12 | 13 | # 14 | # Prototype 15 | # declares an interface for cloning itself 16 | # 17 | class Prototype: 18 | def clone(self): 19 | pass 20 | 21 | def getType(self): 22 | pass 23 | 24 | # 25 | # Concrete Prototypes 26 | # implement an operation for cloning itself 27 | # 28 | class ConcretePrototypeA(Prototype): 29 | def clone(self): 30 | return copy.deepcopy(self) 31 | 32 | def getType(self): 33 | return "type A" 34 | 35 | class ConcretePrototypeB(Prototype): 36 | def clone(self): 37 | return copy.deepcopy(self) 38 | 39 | def getType(self): 40 | return "type B" 41 | 42 | # 43 | # Client 44 | # creates a new object by asking a prototype to clone itself 45 | # 46 | class Client: 47 | def __init__(self): 48 | self._types = [ConcretePrototypeA(), ConcretePrototypeB()] 49 | 50 | def make(self, index): 51 | return self._types[index].clone() 52 | 53 | 54 | if __name__ == "__main__": 55 | client = Client() 56 | 57 | prototype = client.make(0) 58 | print(prototype.getType()) 59 | 60 | prototype = client.make(1) 61 | print(prototype.getType()) -------------------------------------------------------------------------------- /prototype/README.md: -------------------------------------------------------------------------------- 1 | ## Prototype 2 | 3 | Specify the kinds of objects to create using a prototypical instance, and create 4 | new objects by copying this prototype. Pattern has creational purpose and deals 5 | with object relationships, which are more dynamic. The pattern hides the complexities 6 | of making new instances from the client. 7 | 8 | ### When to use 9 | 10 | * when the classes to instantiate are specified at run-time 11 | * to avoid building a class hierarchy of factories that parallels the class hierarchy of products 12 | * when instances of a class can have one of only a few different combinations of state 13 | -------------------------------------------------------------------------------- /proxy/Proxy.py: -------------------------------------------------------------------------------- 1 | # 2 | # Python Design Patterns: Proxy 3 | # Author: Jakub Vojvoda [github.com/JakubVojvoda] 4 | # 2016 5 | # 6 | # Source code is licensed under MIT License 7 | # (for more details see LICENSE) 8 | # 9 | 10 | import sys 11 | 12 | # 13 | # Subject 14 | # defines the common interface for RealSubject and Proxy 15 | # so that a Proxy can be used anywhere a RealSubject is expected 16 | # 17 | class Subject: 18 | def request(self): 19 | pass 20 | 21 | # 22 | # Real Subject 23 | # defines the real object that the proxy represents 24 | # 25 | class RealSubject(Subject): 26 | def __init__(self): 27 | Subject.__init__(self) 28 | 29 | def request(self): 30 | print("Real Subject request.") 31 | 32 | # 33 | # Proxy 34 | # maintains a reference that lets the proxy access the real subject 35 | # 36 | class Proxy(Subject): 37 | def __init__(self): 38 | Subject.__init__(self) 39 | self._subject = RealSubject() 40 | 41 | def request(self): 42 | self._subject.request() 43 | 44 | 45 | if __name__ == "__main__": 46 | proxy = Proxy() 47 | proxy.request() 48 | -------------------------------------------------------------------------------- /proxy/README.md: -------------------------------------------------------------------------------- 1 | ## Proxy 2 | 3 | Proxy pattern provides a surrogate or placeholder for another object to control access to it. 4 | The pattern has structural purpose and applies to objects. 5 | 6 | ### When to use 7 | 8 | * whenever there is a need for a more versatile or sophisticated reference to an object than a simple pointer 9 | -------------------------------------------------------------------------------- /singleton/README.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JakubVojvoda/design-patterns-python/eb0bc23ccdbecc6c51043df7917b8a3f7568eb74/singleton/README.md -------------------------------------------------------------------------------- /singleton/Singleton.py: -------------------------------------------------------------------------------- 1 | # 2 | # Python Design Patterns: Singleton 3 | # Author: Jakub Vojvoda [github.com/JakubVojvoda] 4 | # 2016 5 | # 6 | # Source code is licensed under MIT License 7 | # (for more details see LICENSE) 8 | # 9 | 10 | import sys 11 | 12 | # 13 | # Singleton 14 | # has variable to hold one instance of the class and 15 | # method which gives us a way to instantiate the class 16 | # 17 | # reference: http://stackoverflow.com/questions/31875 18 | # 19 | class Singleton: 20 | def __init__(self, instance): 21 | self._instance = instance 22 | 23 | def get(self): 24 | try: 25 | return self._only 26 | except AttributeError: 27 | self._only = self._instance() 28 | return self._only 29 | 30 | def __call__(self): 31 | raise TypeError("...") 32 | 33 | @Singleton 34 | class Class: 35 | def tell(self): 36 | print("This is singleton.") 37 | 38 | 39 | if __name__ == "__main__": 40 | singleton = Class.get() 41 | singleton.tell() -------------------------------------------------------------------------------- /state/README.md: -------------------------------------------------------------------------------- 1 | ## State 2 | 3 | The pattern allows an object to alter its behavior when its internal state changes. 4 | The object will appear to change its class. It has behavioral purpose and applies 5 | to the objects. 6 | 7 | ### When to use 8 | 9 | * when an object's behavior depends on its state, and it must change its behavior at run-time depending on that state 10 | * operations have large, multipart conditional statements that depend on the object's state -------------------------------------------------------------------------------- /state/State.py: -------------------------------------------------------------------------------- 1 | # 2 | # Python Design Patterns: State 3 | # Author: Jakub Vojvoda [github.com/JakubVojvoda] 4 | # 2016 5 | # 6 | # Source code is licensed under MIT License 7 | # (for more details see LICENSE) 8 | # 9 | 10 | import sys 11 | 12 | # 13 | # State 14 | # defines an interface for encapsulating the behavior associated 15 | # with a particular state of the Context 16 | # 17 | class State: 18 | def handle(self): 19 | pass 20 | 21 | # 22 | # Concrete States 23 | # each subclass implements a behavior associated with a state 24 | # of the Context 25 | # 26 | class ConcreteStateA(State): 27 | def __init__(self): 28 | State.__init__(self) 29 | 30 | def handle(self): 31 | print("State A handled.") 32 | 33 | class ConcreteStateB(State): 34 | def __init__(self): 35 | State.__init__(self) 36 | 37 | def handle(self): 38 | print("State B handled.") 39 | 40 | # 41 | # Context 42 | # defines the interface of interest to clients 43 | # 44 | class Context: 45 | def __init__(self): 46 | self._state = State() 47 | 48 | def setState(self, state): 49 | self._state = state 50 | 51 | def request(self): 52 | self._state.handle() 53 | 54 | 55 | if __name__ == "__main__": 56 | stateA = ConcreteStateA() 57 | stateB = ConcreteStateB() 58 | 59 | context = Context() 60 | 61 | context.setState(stateA) 62 | context.request() 63 | 64 | context.setState(stateB) 65 | context.request() 66 | -------------------------------------------------------------------------------- /strategy/README.txt: -------------------------------------------------------------------------------- 1 | ## Strategy 2 | 3 | Strategy defines a family of algorithms, encapsulates each one, and makes them 4 | interchangeable. It lets the algorithm vary independently fromclients that use it. 5 | The pattern has behavioral purpose and applies to the objects. 6 | 7 | ### When to use 8 | 9 | * many related classes differ only in their behavior 10 | * you need different variants of an algorithm 11 | * an algorithm uses data that clients shouldn't know about -------------------------------------------------------------------------------- /strategy/Strategy.py: -------------------------------------------------------------------------------- 1 | # 2 | # Python Design Patterns: Strategy 3 | # Author: Jakub Vojvoda [github.com/JakubVojvoda] 4 | # 2016 5 | # 6 | # Source code is licensed under MIT License 7 | # (for more details see LICENSE) 8 | # 9 | 10 | import sys 11 | 12 | # 13 | # Strategy 14 | # declares an interface common to all supported algorithms 15 | # 16 | class Strategy: 17 | def algorithmInterface(self): 18 | pass 19 | 20 | # 21 | # Concrete Strategies 22 | # implement the algorithm using the Strategy interface 23 | # 24 | class ConcreteStrategyA(Strategy): 25 | def __init__(self): 26 | Strategy.__init__(self) 27 | 28 | def algorithmInterface(self): 29 | print("Concrete Strategy A") 30 | 31 | class ConcreteStrategyB(Strategy): 32 | def __init__(self): 33 | Strategy.__init__(self) 34 | 35 | def algorithmInterface(self): 36 | print("Concrete Strategy B") 37 | 38 | class ConcreteStrategyC(Strategy): 39 | def __init__(self): 40 | Strategy.__init__(self) 41 | 42 | def algorithmInterface(self): 43 | print("Concrete Strategy C") 44 | 45 | # 46 | # Context 47 | # maintains a reference to a Strategy object 48 | # 49 | class Context: 50 | def __init__(self, strategy): 51 | self._strategy = strategy 52 | 53 | def contextInterface(self): 54 | self._strategy.algorithmInterface() 55 | 56 | 57 | if __name__ == "__main__": 58 | strategy = ConcreteStrategyA() 59 | 60 | context = Context(strategy) 61 | context.contextInterface() 62 | -------------------------------------------------------------------------------- /template-method/README.txt: -------------------------------------------------------------------------------- 1 | ## Template Method 2 | 3 | Template method defines the skeleton of an algorithm in an operation, deferring some 4 | steps to subclasses. It lets subclasses redefine certain steps of an algorithm 5 | without changing the algorithm's structure. The pattern has behavioral purpose and 6 | applies to the classes. 7 | 8 | ### When to use 9 | 10 | * to implement the invariant parts of an algorithm once and leave it up to subclasses to implement the behavior that can vary 11 | * when common behavior among subclasses should be factored and localizedin a common class to avoid code duplication 12 | * to control subclasses extensions -------------------------------------------------------------------------------- /template-method/TemplateMethod.py: -------------------------------------------------------------------------------- 1 | # 2 | # Python Design Patterns: Template Method 3 | # Author: Jakub Vojvoda [github.com/JakubVojvoda] 4 | # 2016 5 | # 6 | # Source code is licensed under MIT License 7 | # (for more details see LICENSE) 8 | # 9 | 10 | import sys 11 | 12 | # 13 | # AbstractClass 14 | # implements a template method defining the skeleton of an algorithm 15 | # 16 | class AbstractClass: 17 | def templateMethod(self): 18 | self.primitiveOperation1() 19 | self.primitiveOperation2() 20 | 21 | def primitiveOperation1(self): 22 | pass 23 | 24 | def primitiveOperation2(self): 25 | pass 26 | 27 | # 28 | # Concrete Class 29 | # implements the primitive operations to carry out specific steps 30 | # of the algorithm, there may be many Concrete classes, each implementing 31 | # the full set of the required operation 32 | # 33 | class ConcreteClass(AbstractClass): 34 | def __init__(self): 35 | AbstractClass.__init__(self) 36 | 37 | def primitiveOperation1(self): 38 | print("Primitive operation 1") 39 | 40 | def primitiveOperation2(self): 41 | print("Primitive operation 2") 42 | 43 | 44 | if __name__ == "__main__": 45 | tm = ConcreteClass() 46 | tm.templateMethod() 47 | -------------------------------------------------------------------------------- /visitor/README.md: -------------------------------------------------------------------------------- 1 | ## Visitor 2 | 3 | Visitor represents an operation to be performed on the elements of an object 4 | structure. It lets you define a new operation without changing the classes of 5 | the elements on which it operates. The pattern has behavioral purpose and applies 6 | to the objects. 7 | 8 | ### When to use 9 | 10 | * an object structure contains many classes of objects with differing interfaces, 11 | and you want to perform operations on these objects that depend on their concrete classes 12 | * many distinct and unrelated operations need to be performed on objects in an object structure, 13 | and you want to avoid "polluting" their classes with these operations 14 | * the classes defining the object structure rarely change, but you often want 15 | to define new operations over the structure -------------------------------------------------------------------------------- /visitor/Visitor.py: -------------------------------------------------------------------------------- 1 | # 2 | # Python Design Patterns: Visitor 3 | # Author: Jakub Vojvoda [github.com/JakubVojvoda] 4 | # 2016 5 | # 6 | # Source code is licensed under MIT License 7 | # (for more details see LICENSE) 8 | # 9 | 10 | import sys 11 | 12 | # 13 | # Visitor 14 | # declares a Visit operation for each class of ConcreteElement 15 | # in the object structure 16 | # 17 | class Visitor: 18 | def visitElementA(self, element): 19 | pass 20 | 21 | def visitElemeentB(self, element): 22 | pass 23 | 24 | # 25 | # Concrete Visitors 26 | # implement each operation declared by Visitor, which implement 27 | # a fragment of the algorithm defined for the corresponding class 28 | # of object in the structure 29 | # 30 | class ConcreteVisitor1(Visitor): 31 | def __init__(self): 32 | Visitor.__init__(self) 33 | 34 | def visitElementA(self, concreteElementA): 35 | print("Concrete Visitor 1: Element A visited.") 36 | 37 | def visitElementB(self, concreteElementB): 38 | print("Concrete Visitor 1: Element B visited.") 39 | 40 | class ConcreteVisitor2(Visitor): 41 | def __init__(self): 42 | Visitor.__init__(self) 43 | 44 | def visitElementA(self, concreteElementA): 45 | print("Concrete Visitor 2: Element A visited.") 46 | 47 | def visitElementB(self, concreteElementB): 48 | print("Concrete Visitor 2: Element B visited.") 49 | 50 | # 51 | # Element 52 | # defines an accept operation that takes a visitor as an argument 53 | # 54 | class Element: 55 | def accept(self, visitor): 56 | pass 57 | 58 | # 59 | # Concrete Elements 60 | # implement an accept operation that takes a visitor as an argument 61 | # 62 | class ConcreteElementA(Element): 63 | def __init__(self): 64 | Element.__init__(self) 65 | 66 | def accept(self, visitor): 67 | visitor.visitElementA(self) 68 | 69 | class ConcreteElementB(Element): 70 | def __init__(self): 71 | Element.__init__(self) 72 | 73 | def accept(self, visitor): 74 | visitor.visitElementB(self) 75 | 76 | 77 | if __name__ == "__main__": 78 | elementA = ConcreteElementA() 79 | elementB = ConcreteElementB() 80 | 81 | visitor1 = ConcreteVisitor1() 82 | visitor2 = ConcreteVisitor2() 83 | 84 | elementA.accept(visitor1) 85 | elementA.accept(visitor2) 86 | 87 | elementB.accept(visitor1) 88 | elementB.accept(visitor2) 89 | --------------------------------------------------------------------------------