{"id":13392888,"url":"https://github.com/tylerlaberge/PyPattyrn","last_synced_at":"2025-03-13T19:31:11.577Z","repository":{"id":37887174,"uuid":"63554602","full_name":"tylerlaberge/PyPattyrn","owner":"tylerlaberge","description":"A simple library for implementing common design patterns.","archived":true,"fork":false,"pushed_at":"2024-05-26T00:24:11.000Z","size":243,"stargazers_count":2293,"open_issues_count":0,"forks_count":154,"subscribers_count":66,"default_branch":"master","last_synced_at":"2025-03-02T00:19:06.607Z","etag":null,"topics":["design-patterns","library","python"],"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/tylerlaberge.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.md","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":"2016-07-17T22:09:31.000Z","updated_at":"2025-03-01T20:31:30.000Z","dependencies_parsed_at":"2024-06-18T17:06:08.593Z","dependency_job_id":"7bef5dd5-939d-428b-9120-15007b767fb4","html_url":"https://github.com/tylerlaberge/PyPattyrn","commit_stats":{"total_commits":97,"total_committers":3,"mean_commits":"32.333333333333336","dds":0.04123711340206182,"last_synced_commit":"6561e9927553a9074d0a71247a1b1e933f2ec423"},"previous_names":[],"tags_count":3,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tylerlaberge%2FPyPattyrn","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tylerlaberge%2FPyPattyrn/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tylerlaberge%2FPyPattyrn/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tylerlaberge%2FPyPattyrn/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/tylerlaberge","download_url":"https://codeload.github.com/tylerlaberge/PyPattyrn/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243469131,"owners_count":20295692,"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":["design-patterns","library","python"],"created_at":"2024-07-30T17:00:38.710Z","updated_at":"2025-03-13T19:31:11.208Z","avatar_url":"https://github.com/tylerlaberge.png","language":"Python","funding_links":[],"categories":["Programming Language Design Patterns","Algorithms and Design Patterns","Language/Framework design patterns (mainly GoF)","算法和设计模式","Python","GoF design patterns (Language/Framework specifc)","Algorithms and Design Patterns [🔝](#readme)","Algorithms \u0026 Design Patterns","参考和论坛","资源列表","Awesome Python"],"sub_categories":["参考","算法和设计模式","Algorithms and Design Patterns"],"readme":"## **NOTE: This repository is not maintained and should not be used. Most of the design patterns implemented in this repository are not really needed when writing idomatic Python.**\n\n\n\n# PyPattyrn\n\n```python\nfrom pypattyrn.creational.singleton import Singleton\n\nclass DummyClass(object, metaclass=Singleton):  #  DummyClass is now a Singleton!\n    ...\n```\n\nPyPattyrn is a python package aiming to make it easier and faster to implement design patterns into your own projects.\n\nDesign patterns by nature cannot be directly translated into code as they are just a description of how to solve a particular problem. However, many of the common design patterns have boilerplate code that is common throughout all implementations of the pattern. This package captures that common code and makes it easy to use so that you dont have to write it yourself in all your projects.\n___\n\n### Contents\n___\n* [Installation](https://github.com/tylerlaberge/PyPattyrn#installation)\n* [Examples](https://github.com/tylerlaberge/PyPattyrn#examples)\n  * [Behavioral Patterns](https://github.com/tylerlaberge/PyPattyrn#behavioral-patterns)\n    * [Chain of Responsibility](https://github.com/tylerlaberge/PyPattyrn#chain-of-responsibility-pattern)\n    * [Command](https://github.com/tylerlaberge/PyPattyrn#command-pattern)\n    * [Iterator](https://github.com/tylerlaberge/PyPattyrn#iterator-pattern)\n    * [Mediator](https://github.com/tylerlaberge/PyPattyrn#mediator-pattern)\n    * [Memento](https://github.com/tylerlaberge/PyPattyrn#memento-pattern)\n    * [Null Object](https://github.com/tylerlaberge/PyPattyrn#null-object-pattern)\n    * [Observer](https://github.com/tylerlaberge/PyPattyrn#observer-pattern)\n    * [Visitor](https://github.com/tylerlaberge/PyPattyrn#visitor-pattern)\n  * [Creational Patterns](https://github.com/tylerlaberge/PyPattyrn#creational-patterns)\n    * [Builder](https://github.com/tylerlaberge/PyPattyrn#builder-pattern)\n    * [Factory](https://github.com/tylerlaberge/PyPattyrn#factory-pattern)\n    * [Abstract Factory](https://github.com/tylerlaberge/PyPattyrn#abstract-factory-pattern)\n    * [Object Pool](https://github.com/tylerlaberge/PyPattyrn#object-pool-pattern)\n    * [Prototype](https://github.com/tylerlaberge/PyPattyrn#prototype-pattern)\n    * [Singleton](https://github.com/tylerlaberge/PyPattyrn#singleton-pattern)\n  * [Structural Patterns](https://github.com/tylerlaberge/PyPattyrn#structural-patterns)\n    * [Adapter](https://github.com/tylerlaberge/PyPattyrn#adapter-pattern)\n    * [Composite](https://github.com/tylerlaberge/PyPattyrn#composite-pattern)\n    * [Decorator](https://github.com/tylerlaberge/PyPattyrn#decorator-pattern)\n    * [Flyweight](https://github.com/tylerlaberge/PyPattyrn#flyweight-pattern)\n* [Resources](https://github.com/tylerlaberge/PyPattyrn#resources)\n\n___\n### Installation\n___\n```\npip install pypattyrn\n```\n\nor\n\n```\ngit clone https://github.com/tylerlaberge/PyPattyrn.git\ncd PyPattyrn\npython setup.py install\n```\n\n___\n### Examples\n___\n\n#### Behavioral Patterns\n\nPatterns which deal with communication between objects.\n___\n##### Chain of Responsibility Pattern\n\nPass a request along a chain of objects until the request is handled.\n\n```python\nfrom pypattyrn.behavioral.chain import Chain, ChainLink\n\n\nclass ConcreteChainLinkThree(ChainLink): # This object is a ChainLink\n\n    def handle(self, request): # Implement the handle method.\n        if request == 'handle_three':\n            return \"Handled in chain link three\"\n        else:\n            return self.successor_handle(request) # If this ChainLink can't handle the request, \n                                                  # ask its successor to handle it. \n                                                  # (Has no successor so will raise AttributeError)\n                                                  # (This exception is caught and will call a Chains fail method)\n\n\nclass ConcreteChainLinkTwo(ChainLink): # This object is a ChainLink\n\n    def __init__(self): # Override init to set a successor on initialization.\n        super().__init__() # first call ChainLinks init\n        self.set_successor(ConcreteChainLinkThree()) # Set the successor of this chain link \n                                                     # to a ConcreteChainLinkThree instance.\n\n    def handle(self, request): # Implement the handle method.\n        if request == 'handle_two':\n            return \"Handled in chain link two\"\n        else:\n            return self.successor_handle(request) # If this ChainLink can't handle a request \n                                                  # ask its successor to handle it \n                                                  # (the ConcreteChainLinkThree instance).\n\n\nclass ConcreteChainLinkOne(ChainLink): # This object is a ChainLink\n\n    def __init__(self): \n        super().__init__()\n        self.set_successor(ConcreteChainLinkTwo()) # Set the successor of this ChainLink\n                                                   # to a ConcreteChainLinkTwo instance.\n\n    def handle(self, request): # Implement the handle method.\n        if request == 'handle_one':\n            return \"Handled in chain link one\"\n        else:\n            return self.successor_handle(request) # If this ChainLink can't handle a request \n                                                  # ask its successor to handle it \n                                                  # (the ConcreteChainLinkTwo instance).\n\nclass ConcreteChain(Chain): # This object is a Chain\n\n    def __init__(self): # Override init to initialize a Chain with the starting chain link.\n        super().__init__(ConcreteChainLinkOne()) # Initialize this Chain with a start chain link.\n                                                 # (a ConcreteChainLinkOne instance)\n\n    def fail(self): # Implement the fail method, this is called if no chain links could handle a request.\n        return 'Fail'\n\n\nchain = ConcreteChain()\n\nassert \"Handled in chain link one\" == chain.handle(\"handle_one\")\nassert \"Handled in chain link two\" == chain.handle(\"handle_two\")\nassert \"Handled in chain link three\" == chain.handle(\"handle_three\")\nassert \"Fail\" == chain.handle('handle_four')\n```\n##### Command Pattern\n\nEncapsulate information for performing an action into an object.\n\n```python\nfrom pypattyrn.behavioral.command import Receiver, Command, Invoker\n\n\nclass Thermostat(Receiver): # This object is a Receiver. \n                            # Contains methods for commands to use.\n\n    def raise_temp(self, amount):\n        return \"Temperature raised by {0} degrees\".format(amount)\n\n    def lower_temp(self, amount):\n        return \"Temperature lowered by {0} degrees\".format(amount)\n\n\nclass RaiseTempCommand(Command): # This object is a Command.\n\n    def __init__(self, receiver, amount=5): # Override init to include a temperature amount argument.\n        super().__init__(receiver)\n        self.amount = amount\n\n    def execute(self): # Implement the execute method.\n        return self._receiver.action('raise_temp', self.amount) # Call on the Receiver's action method  with \n                                                                # the name of the method to call and args.\n                                                                # (Raises the temperature by 5 degrees.)\n\n    def unexecute(self): # Implement the unexecute method.\n        return self._receiver.action('lower_temp', self.amount) # Calls on the Receiver to lower \n                                                                # the temperature by 5 degrees.\n                                                     \n\nclass LowerTempCommand(Command): # This object is a Command.\n \n   def __init__(self, receiver, amount=5):\n        super().__init__(receiver)\n        self.amount = amount\n\n    def execute(self):\n        return self._receiver.action('lower_temp', self.amount) # Call on the receiver to lower the\n                                                                # temperature by 5 degrees.\n\n    def unexecute(self):\n        return self._receiver.action('raise_temp', self.amount) # Call on the receiver to raise the \n                                                                # temperature by 5 degrees.\n\n\nclass Worker(Invoker): # This object is the Invoker\n\n    def __init__(self): # Override init to initialize an Invoker with Commands to accept.\n        super().__init__([LowerTempCommand, RaiseTempCommand]) # Initialize the Invoker with the\n                                                               # LowerTempCommand and RaiseTempCommand classes.\n\n\nthermostat = Thermostat() # Create a Receiver.\nworker = Worker() # Create an Invoker.\n\nassert \"Temperature lowered by 5 degrees\" == worker.execute(LowerTempCommand(thermostat)) # Have the Invoker execute a LowerTempCommand\n                                                                                          # which uses the thermostat Receiver.\nassert \"Temperature raised by 5 degrees\" == worker.execute(RaiseTempCommand(thermostat)) # Have the Invoker execute a RaiseTempCommand\n                                                                                          # which uses the thermostat Receiver.\nassert \"Temperature lowered by 5 degrees\" == worker.undo() # Undo the previous command (Calls the RaiseTempCommand unexecute method.)\n```\n\n##### Iterator Pattern\n\nA way of sequentially accessing elements in a collection.\n\n```python\nfrom pypattyrn.behavioral.iterator import Iterable, Iterator\n\n\nclass Counter(Iterable): # This object is an Iterable\n\n    def __init__(self, max):\n        self.count = 0\n        self.max = max\n\n    def __next__(self): # Implement the __next__ method.\n        self.count += 1 # Increment the count\n        if self.count \u003e self.max:\n            raise StopIteration() # make sure to raise StopIteration at the appropriate time.\n        else:\n            return self.count - 1 # Return the count\n\n\nclass CounterIterator(Iterator): # This object is an Iterator\n\n    def __init__(self): # Override init to initialize an Iterator with the Counter object.\n        super().__init__(Counter(10)) # Initialize the iterator with a Counter that goes to 10.\n\ncounter_iterator = CounterIterator() # Create a CounterIterator.\n\nfor count in counter_iterator: # You can loop through it how you would expect.\n    print(count)  # 0, 1, 2, 3, ..., 9\n```\n\n##### Mediator Pattern\n\nAn intermediary for managing communications between many objects.\n\n```python\nfrom pypattyrn.behavioral.mediator import Mediator\n\n\nclass Dog(object):\n    sound = ''\n\n    def set_sound(self, sound):\n        self.sound = sound\n\n\nclass Cat(object):\n    sound = ''\n\n    def set_sound(self, sound):\n        self.sound = sound\n\n\ndog = Dog()\ncat = Cat()\n\nmediator = Mediator() # Create a Mediator object.\n\nmediator.connect('set_dog_sound', dog.set_sound) # Connect the signal 'set_dog_sound' to the dog.set_sound method.\nmediator.connect('set_cat_sound', cat.set_sound) # Connect the signal 'set_cat_sound' to the cat.set_sound method.\n\nmediator.connect('set_sound', dog.set_sound) # Also connect the signal 'set_sound' to the dog.set_sound method.\nmediator.connect('set_sound', cat.set_sound) # Also connect the signal 'set_sound' to the cat.set_sound method.\n\nmediator.signal('set_sound', 'foo') # Send out the signal 'set_sound' \n                                    # with an argument to be passed to the connected methods.\n                                    # (Sets dog.sound and cat.sound to 'foo')\n\n\nassert 'foo' == dog.sound \nassert 'foo' == cat.sound\n\nmediator.signal('set_dog_sound', 'woof') # Send out the signal 'set_dog_sound'\n                                         # (Sets dog.sound to 'woof')\nmediator.signal('set_cat_sound', 'meow') # Send out the signal 'set_cat_sound'\n                                         # (Sets cat.sound to 'meow')\n\nassert 'woof' == dog.sound\nassert 'meow' == cat.sound\n\nmediator.disconnect('set_sound', dog.set_sound) # Disconnect the method dog.sound from the signal 'set_sound'\n\nmediator.signal('set_sound', 'bar') # Send out the signal 'set_sound'\n                                    # (Only sets cat.sound to 'bar' because we disconnected dog.sound)\n\nassert 'woof' == dog.sound\nassert 'bar' == cat.sound\n```\n\n##### Memento Pattern\n\nSave the state of an object and rollback to it at a later time.\n\n```python\nfrom pypattyrn.behavioral.memento import Originator\n\n\nclass Cat(Originator): # This object is an Originator\n    def __init__(self, name):\n        self.name = name\n\n\ncat = Cat('Tom') # Initialize a Cat with the name 'Tom'\nassert cat.name == 'Tom'\n\ncat_memento = cat.commit() # Save the cats current state to a Memento object.\ncat.name = 'jerry' # Change the cats name to 'jerry'\nassert cat.name == 'jerry'\n\ncat.rollback(cat_memento) # Restore the cats state to the memento object we saved.\nassert 'Tom' == cat.name # The cats name was changed back to 'Tom' as expected.\n```\n\n##### Null Object Pattern\n\nEncapsulate the absence of an object into an object with neutral behavior.\n\n```python\nfrom pypattyrn.behavioral.null import Null\n\n# You can initialize a Null object with any parameters.\ntry:\n    Null()\n    Null('value')\n    Null('value', param='value')\nexcept:\n    raise AssertionError()\n\nnull = Null()\n\n# Attempting to set parameters won't do anything and won't error\ntry:\n    null.foo = 'foo' \n    null.foo.bar = 'bar'\nexcept:\n    raise AssertionError()\n\n# Calling on a null object in any way will just return that null object.\n\nassert null == null()\nassert null == null('value')\nassert null == null('value', param='value')\nassert null == null.foo\nassert null == null.foo.bar\nassert null == null.foo.bar.method1()\nassert null == null.foo.bar.method1().method2('foo', bar='bar').attr3\n\nassert str(null) == '' # Null objects string representation is the empty string.\nassert repr(null) == '' # Null objects repr is the empty string.\nassert bool(null) is False # Null object evaluates to False as a boolean.\n\n# Trying to delete attributes doesn't do anything and won't error.\ntry:\n    del null.foo \n    del null.foo.bar\nexcept:\n    raise AssertionError()\n```\n\n##### Observer Pattern\n\nNotify many objects when a single object's state changes.\n\n```python\nfrom pypattyrn.behavioral.observer import Observable, Observer\n\n\nclass ConcreteObservable(Observable): # This object is an Observable.\n    _kinda_private_var = 'I am kinda private'\n    __private_var = 'I am more private'\n\n    def change_state(self, **kwargs): # Some method to change this objects state and notify observers.\n        for key, value in kwargs.items():\n            setattr(self, key, value) # Change the objects state.\n\n        self.notify() # Notify all observers of the change in state.\n                      # Will call the update method of each attached observer with kwargs that come\n                      # from this objects __dict__ attribute, minus any private variables (starts with __ or _)\n\n\nclass ConcreteObserver(Observer): # This object is an Observer.\n    updated_state = None\n\n    def update(self, **state): # Implement the update method. \n                               # Called when an attached observable calls its notify method.\n        self.updated_state = state\n\n\nobservable = ConcreteObservable() # Create an Observable\nobserver_1 = ConcreteObserver() # Create Observers\nobserver_2 = ConcreteObserver()\nobserver_3 = ConcreteObserver()\n\nobservable.attach(observer_1) # Attach each of the Observers to the Observable\nobservable.attach(observer_2)\nobservable.attach(observer_3)\n\nobservable.change_state(foo='foo', bar='bar') # Change the Observable's state.\n                                              # Also calls notify which will call each Observers update method.\n\nexpected_state = {'foo': 'foo', 'bar': 'bar'} \n\n# Make sure each Observers state was changed accordingly when the notify method was called by the Observable.\n\nassert sorted(expected_state.keys()) == sorted(observer_1.updated_state.keys()) and \\\n       sorted(expected_state.values()) == sorted(observer_1.updated_state.values())\n\nassert sorted(expected_state.keys()) == sorted(observer_2.updated_state.keys()) and \\\n       sorted(expected_state.values()) == sorted(observer_2.updated_state.values())\n\nassert sorted(expected_state.keys()) == sorted(observer_3.updated_state.keys()) and \\\n       sorted(expected_state.values()) == sorted(observer_3.updated_state.values())\n\nobservable.detach(observer_1) # Detach Observer 1 from the Observable\nobservable.change_state(bar='foobar') # Change the Observables state.\nexpected_state_2 = {'foo': 'foo', 'bar': 'foobar'}\n\n# Make sure each Observers state was changed accordingly when notify was called by the Observable,\n# Except for observer_1 because we detached that Observer from the Observable.\n\nassert sorted(expected_state_2.keys()) != sorted(observer_1.updated_state.keys()) or \\\n       sorted(expected_state_2.values()) != sorted(observer_1.updated_state.values())\n\nassert sorted(expected_state_2.keys()) == sorted(observer_2.updated_state.keys()) and \\\n       sorted(expected_state_2.values()) == sorted(observer_2.updated_state.values())\n\nassert sorted(expected_state_2.keys()) == sorted(observer_3.updated_state.keys()) and \\\n       sorted(expected_state_2.values()) == sorted(observer_3.updated_state.values())\n```\n\n##### Visitor Pattern\n\nAdd new operations to an existing class without modifying it.\n\n```python\nfrom pypattyrn.behavioral.visitor import Visitee, Visitor\n\n\nclass A(Visitee): # This object is a Visitee\n    pass\n\n\nclass B(A): # This object is an A, which also makes this a Visitee.\n    pass\n\n\nclass C(B): # This object is a B, which also makes this a Visitee.\n    pass\n\n\nclass D(Visitee): # This object is a Visitee\n    pass\n\n\nclass NodeVisitor(Visitor): # This object is a Visitor\n\n    def generic_visit(self, node, *args, **kwargs): # Implement the generic visit method.\n                                                    # This is called when there is no visit_ method\n                                                    # implemented for a particular visitee.\n\n        return 'generic_visit ' + node.__class__.__name__\n\n    def visit_b(self, node, *args, **kwargs): # Called when this object visits a Visitee of class 'B'.\n        return 'visit_b ' + node.__class__.__name__\n\n    def visit_d(self, node, *args, **kwargs): # Called when this object visits a Visitee of class 'D'.\n        return 'visit_d {0} args: {1} kwargs: {2}'.format(node.__class__.__name__, args, kwargs)\n\n# Create Visitee's\nnode_a = A()\nnode_b = B()\nnode_c = C()\nnode_d = D()\n\n# Create Visitor\nnode_visitor = NodeVisitor()\n\nassert 'generic_visit A' == node_a.accept(node_visitor) # Visit node_a with the Visitor.\n                                                        # Since the visitor does not have a visit_a method,\n                                                        # generic_visit is called.\nassert 'visit_b B' == node_b.accept(node_visitor) # Visit node_b with the Visitor.\n                                                  # Calls the visitors visit_b method.\nassert 'visit_b C' == node_c.accept(node_visitor) # Visit node_c with the Visitor.\n                                                  # Even though the visitor does not have a visit_c method, \n                                                  # since node_c inherits B, the Visitors visit_b method is called.\n\n# Visit node_d with the Visitor. Calls the visitors visit_d method.\nassert \"visit_d D args: ('foo', 'bar') kwargs: {'foobar': 'foobar'}\" == node_d.accept(node_visitor,\n                                                                                      'foo', 'bar',\n                                                                                      foobar='foobar')\n```\n\n___\n#### Creational Patterns\n\nPatterns which deal with object creation.\n___\n\n##### Builder Pattern\n\nSeparate object construction from its representation.\n\n```python\nfrom pypattyrn.creational.builder import Builder, Director\n\n\nclass Building(object):  # The object being constructed.\n\n    def __init__(self):\n        self.floor = None\n        self.size = None\n\n    def __repr__(self):\n        return 'Floor: {0.floor} | Size: {0.size}'.format(self)\n\n\nclass HomeBuilder(Builder):  # A base Builder class for constructing homes.\n\n    def __init__(self):\n        super().__init__(Building())  # Initialize the Builder class with a Building instance.\n        self._register('floor', self._build_floor)  # Register the keyword 'floor' with the _build_floor method.\n        self._register('size', self._build_size)  # Register the keyword 'size' with the _build_size method.\n\n    def _build_floor(self):\n        pass\n\n    def _build_size(self):\n        pass\n\n\nclass HouseBuilder(HomeBuilder):  # A concrete HomeBuilder class for constructing houses\n\n    def _build_floor(self):\n        self.constructed_object.floor = 'One'  # Alter the Building's floor attribute.\n\n    def _build_size(self):\n        self.constructed_object.size = 'Big'  # Alter the Building's size attribute.\n\n\nclass FlatBuilder(HomeBuilder):  # A concrete HomeBuilder class for constructing flats\n\n    def _build_floor(self):\n        self.constructed_object.floor = 'More than one'  # Alter the Building's floor attribute.\n\n    def _build_size(self):\n        self.constructed_object.size = 'Small'  # Alter the Building's size attribute.\n\n\nclass HomeDirector(Director):  # A Director class for managing home construction.\n\n    def construct(self):\n        self.builder.build('floor')  # Build the floor part of the Building by using the keyword 'floor'\n        self.builder.build('size')  # Build the size part of the Building by using the keyword 'size'\n\n\nhome_director = HomeDirector()\n\nhome_director.builder = HouseBuilder()  # Use the house builder.\nhome_director.construct()  # Construct the house.\nhouse = home_director.get_constructed_object()  # Get the constructed house.\nprint(repr(house))    #Floor: One | Size: Big\n    \nhome_director.builder = FlatBuilder()  # Use the flat builder.\nhome_director.construct()  # Construct the flat.\nhouse = home_director.get_constructed_object()  # Get the constructed flat.\nprint(repr(house))    #Floor: More than one | Size: Small\n```\n\n##### Factory Pattern\n\nAn interface for creating an object.\n\n```python\nfrom pypattyrn.creational.factory import Factory  # This is just an interface\n\n\nclass Cat(object):\n\n    def speak(self):\n        print('meow')\n\n\nclass Dog(object):\n\n    def speak(self):\n        print('woof')\n\n\nclass AnimalFactory(Factory):  # A factory class for creating animals.\n\n    def create(self, animal_type):  # Implement the abstract create method.\n        if animal_type == 'cat':\n            return Cat()\n        elif animal_type == 'dog':\n            return Dog()\n        else:\n            return None\n\n\nanimal_factory = AnimalFactory()\n\ncat = animal_factory.create('cat')\ndog = animal_factory.create('dog')\n\ncat.speak()  # 'meow'\ndog.speak()  # 'woof'\n```\n\n##### Abstract Factory Pattern\n\nCreate an instance from a family of factories.\n\n```python\nfrom pypattyrn.creational.factory import Factory, AbstractFactory\n\n\nclass Cat(object):\n\n    def speak(self):\n        print('meow')\n\n\nclass Dog(object):\n\n    def speak(self):\n        print('woof')\n\n\nclass Ant(object):\n\n    def march(self):\n        print('march')\n\n\nclass Fly(object):\n\n    def fly(self):\n        print('fly')\n\n\nclass AnimalFactory(Factory):  # A factory class for creating animals.\n\n    def create(self, animal_type):  # Implement the abstract create method.\n        if animal_type == 'cat':\n            return Cat()\n        elif animal_type == 'dog':\n            return Dog()\n        else:\n            return None\n\n\nclass InsectFactory(Factory):  # A factory class for creating insects.\n\n    def create(self, insect_type):  # Implement the abstract create method.\n        if insect_type == 'ant':\n            return Ant()\n        elif insect_type == 'fly':\n            return Fly()\n        else:\n            return None\n\n\nclass CreatureFactory(AbstractFactory):  # A Factory class for creating creatures.\n\n    def __init__(self):\n        super().__init__()\n        self._register('insect_factory', InsectFactory())  # Register an InsectFactory with a keyword.\n        self._register('animal_factory', AnimalFactory())  # Register an AnimalFactory with a keyword.\n\n    def create(self, creature_type):  # Implement the Abstract create method.\n        if creature_type == 'cat' or creature_type == 'dog':\n            return self._factories['animal_factory'].create(creature_type)  # Use the AnimalFactory\n        elif creature_type == 'ant' or creature_type == 'fly':\n            return self._factories['insect_factory'].create(creature_type)  # Use the InsectFactory\n        else:\n            return None\n\ncreature_factory = CreatureFactory()\n\ncat = creature_factory.create('cat')\ndog = creature_factory.create('dog')\nant = creature_factory.create('ant')\nfly = creature_factory.create('fly')\n\ncat.speak()  # 'meow'\ndog.speak()  # 'woof'\nant.march()  # 'march'\nfly.fly()  # 'fly'\n```\n\n##### Object Pool Pattern\n\nProvide a pool of instantiated objects which can be checked out and returned rather than creating new objects all the time.\n\n```python\nfrom pypattyrn.creational.pool import Reusable, Pool\n\n\nclass Dog(Reusable):\n    def __init__(self, sound):\n        self.sound = sound\n        super().__init__()\n\n\nclass DogPool(Pool):\n    def __init__(self):\n        super().__init__(Dog, 'woof')\n\n\ndog_pool = DogPool()\n\ndog_one = dog_pool.acquire()\ndog_two = dog_pool.acquire()\ndog_two.sound = 'meow'\n\ndog_pool.release(dog_one)\ndog_three = dog_pool.acquire()\n\ndog_pool.release(dog_two)\ndog_four = dog_pool.acquire()\n\nassert id(dog_one) == id(dog_three)\nassert id(dog_two) == id(dog_four)\nassert dog_one.sound == dog_two.sound\nassert dog_three.sound == dog_four.sound\nassert dog_one.sound == dog_four.sound\n```\n\n##### Prototype Pattern\n\nClone an object to produce new objects.\n\n```python\nfrom pypattyrn.creational.prototype import Prototype\n\n\nclass Point(Prototype):\n    def __init__(self, x, y):\n        self.x = x\n        self.y = y\n\n    def move(self, x, y):\n        self.x += x\n        self.y += y\n\n\npoint_one = Point(15, 15)\npoint_two = point_one.prototype(z=20)\npoint_three = point_two.prototype()\n\nassert point_one.x == point_two.x\nassert point_one.y == point_two.y\nassert not hasattr(point_one, 'z')\nassert hasattr(point_two, 'z')\nassert point_two.z == 20\nassert point_three.__dict__ == point_two.__dict__\n\nfrom math import sqrt\ndef distance_to(this, other):\n    return sqrt((this.x - other.x) ** 2 + (this.y - other.y) ** 2)\n\npoint_four = point_three.prototype(distance_to=distance_to)\n\nassert hasattr(point_four, 'distance_to')\nassert point_four.distance_to(point_three) == 0\n```\n\n##### Singleton Pattern\n\nEnsure that only a single instance of a class exists.\n\n```python\nfrom pypattyrn.creational.singleton import Singleton\n\n\nclass DummySingletonOne(object, metaclass=Singleton):\n\n    def __init__(self):\n        pass\n\n\nclass DummySingletonTwo(object, metaclass=Singleton):\n\n    def __init__(self):\n        pass\n\n\ndummy_class_one_instance_one = DummySingletonOne()\ndummy_class_one_instance_two = DummySingletonOne()\n\ndummy_class_two_instance_one = DummySingletonTwo()\ndummy_class_two_instance_two = DummySingletonTwo()\n\nassert id(dummy_class_one_instance_one) == id(dummy_class_one_instance_two)\nassert id(dummy_class_two_instance_one) == id(dummy_class_two_instance_two)\n\nassert id(dummy_class_one_instance_one) != id(dummy_class_two_instance_one)\nassert id(dummy_class_one_instance_two) != id(dummy_class_two_instance_two)\n```\n___\n\n#### Structural Patterns\n\nPatterns which deal with object composition\n___\n\n##### Adapter Pattern\n\nWrap an object into an interface which the client expects. \n\n```python\nfrom pypattyrn.structural.adapter import Adapter\n\n\nclass Dog(object):\n    def __init__(self):\n        self.name = \"Dog\"\n\n    def bark(self):\n        return \"woof!\"\n\n\nclass Cat(object):\n    def __init__(self):\n        self.name = \"Cat\"\n\n    def meow(self):\n        return \"meow!\"\n\ncat = Cat()\ndog = Dog()\n\ncat_adapter = Adapter(cat, make_noise=cat.meow)\ndog_adapter = Adapter(dog, make_noise=dog.bark)\n\nassert cat_adapter.make_noise == cat.meow\nassert dog_adapter.make_noise == dog.bark\n\nassert cat_adapter.make_noise() == 'meow!'\nassert dog_adapter.make_noise() == 'woof!'\n\nassert cat_adapter.name == 'Cat'\nassert dog_adapter.name == 'Dog'\n\nassert cat_adapter.meow() == 'meow!'\nassert dog_adapter.bark() == 'woof!'\n\nassert cat_adapter.original_dict() == cat.__dict__\nassert dog_adapter.original_dict() == dog.__dict__\n\nbad_cat_adapter = Adapter(cat, foo=cat.name)\n\ntry:\n    bad_cat_adapter.foo\nexcept AttributeError:\n    pass\nelse:\n    raise AssertionError()\n\nbad_dog_adapter = Adapter(dog, make_noise=cat.meow)\n\ntry:\n    bad_dog_adapter.make_noise()\nexcept AttributeError:\n    pass\nelse:\n    raise AssertionError()\n```\n\n##### Composite Pattern\n\nCompose objects into a tree structure of objects that can be treated uniformly.\n\n```python\nfrom pypattyrn.structural.composite import Composite\n\n\nclass Component(object):\n\n    def do_something(self):\n        pass\n\n\nclass Leaf(Component):\n\n    def __init__(self):\n        self.did_something = False\n\n    def do_something(self):\n        self.did_something = True\n\n\nleaf_one = Leaf()\nleaf_two = Leaf()\nleaf_three = Leaf()\n\ncomposite_one = Composite(Component)\ncomposite_two = Composite(Component)\ncomposite_three = Composite(Component)\n\ncomposite_one.add_component(leaf_one)\ncomposite_two.add_component(leaf_two)\ncomposite_three.add_component(leaf_three)\n\ncomposite_two.add_component(composite_three)\ncomposite_one.add_component(composite_two)\n\n\nassert set() == {leaf_one, composite_two}.symmetric_difference(composite_one.components)\nassert set() == {leaf_two, composite_three}.symmetric_difference(composite_two.components)\nassert set() == {leaf_three}.symmetric_difference(composite_three.components)\n\ncomposite_two.remove_component(composite_three)\n\nassert set() == {leaf_two}.symmetric_difference(composite_two.components)\n\nassert not leaf_one.did_something\nassert not leaf_two.did_something\nassert not leaf_three.did_something\n\ncomposite_one.do_something()\n\nassert leaf_one.did_something\nassert leaf_two.did_something\nassert not leaf_three.did_something\n```\n\n##### Decorator Pattern\n\nAttach additional functionality to functions.\n\n```python\nimport time\nfrom pypattyrn.structural.decorator import DecoratorSimple, DecoratorComplex, CallWrapper\n\n\nclass TimeThis(DecoratorSimple):\n\n    def __call__(self, *args, **kwargs):\n        start = time.time()\n        result = self.func(*args, **kwargs)\n        end = time.time() - start\n        return result, end\n\n\nclass SlowClass(object):\n\n    @TimeThis\n    def slow_function(self, n):\n        time.sleep(n)\n        return 'foo'\n\nslow_class = SlowClass()\nresult = slow_class.slow_function(1)\nassert result[0] == 'foo'\nassert 1 \u003c= result[1] \u003c= 2\n\n\nclass Alert(DecoratorComplex):\n\n    def __init__(self, alert_time):\n        self.alert_time = alert_time\n\n    @CallWrapper\n    def __call__(self, func, *args, **kwargs):\n        start = time.time()\n        return_val = func(*args, **kwargs)\n        end = time.time() - start\n        if end \u003e self.alert_time:\n            return return_val, True\n        return return_val, False\n\n\nclass SlowClass(object):\n\n    @Alert(1)\n    def slow_function_true(self, n):\n        time.sleep(n)\n        return n\n\n    @Alert(1)\n    def slow_function_false(self, n):\n        return n\n\n\nslow_class = SlowClass()\nassert (2, True) == slow_class.slow_function_true(2)\nassert (10, False) == slow_class.slow_function_false(10)\n```\n\n##### Flyweight Pattern\n\nShare data with other similar objects to increase efficiency.\n\n```python\nfrom pypattyrn.structural.flyweight import FlyweightMeta\n\n\nclass Card(object, metaclass=FlyweightMeta):\n\n    def __init__(self, suit, value):\n        self.suit = suit\n        self.value = value\n\n\nthree_of_spades = Card('Spade', 3)\nfour_of_spades = Card('Spade', 4)\nthree_of_spades_two = Card('Spade', 3)\n\nassert id(three_of_spades) == id(three_of_spades_two)\nassert id(three_of_spades) != id(four_of_spades)\n```\n___\n\n#### Resources\n___\n\n* [API Documentation](https://tylerlaberge.github.io/PyPattyrn/)\n* [General Design Pattern Information](https://sourcemaking.com/design_patterns)\n\n___\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftylerlaberge%2FPyPattyrn","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftylerlaberge%2FPyPattyrn","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftylerlaberge%2FPyPattyrn/lists"}