#Factory
Factory is great for:
- Uncertainties in types of objects
- Decisions to be made at runtime regarding what classes to use
class Dog:
"""A simple dog class"""
def __init__(self, name):
self._name = name
def speak(self):
return "Woof!"
class Cat:
"""A simple dog class"""
def __init__(self, name):
self._name = name
def speak(self):
return "Meow!"
def get_pet(pet="dog"):
"""The factory method"""
pets = dict(dog=Dog("Hope"), cat=Cat("Peace"))
return pets[pet]
d = get_pet("dog")
print(d.speak())
c = get_pet("cat")
print(c.speak())
The attribute name with a single underscore is called a weak private.In the factory function, the mission is really to create these objects and to return these objects to the user of the function.
#Abstract Factory
Abstract Factory is great for situations when the user expectation yields multiple related object until runtime.
class Dog:
"""One of the objects to be returned"""
def speak(self):
return "Woof!"
def __str__(self):
return "Dog"
class DogFactory:
"""Concrete Factory"""
def get_pet(self):
"""Returns a Dog object"""
return Dog()
def get_food(self):
"""Returns a Dog Food object"""
return "Dog Food!"
class PetStore:
""" PetStore houses our Abstract Factory """
def __init__(self, pet_factory=None):
""" pet_factory is our Abstract Factory """
self._pet_factory = pet_factory
def show_pet(self):
""" Utility method to display the details of the objects retured by the DogFactory """
pet = self._pet_factory.get_pet()
pet_food = self._pet_factory.get_food()
print("Our pet is '{}'!".format(pet))
print("Our pet says hello by '{}'".format(pet.speak()))
print("Its food is '{}'!".format(pet_food))
#Create a Concrete Factory
factory = DogFactory()
#Create a pet store housing our Abstract Factory
shop = PetStore(factory)
#Invoke the utility method to show the details of our pet
shop.show_pet()
Here we have one concrete factory(DogFactory), we can definitely create more concrete factories like CatFactory.
#Singleton
Singletons are used for:
- only one instance
- Global Variable in an object-oriented way
A Singleton acts as an information cache share by multiple objects. Modules in Python act as Singletons.
class Borg:
"""Borg pattern making the class attributes global"""
_shared_data = {} # Attribute dictionary
def __init__(self):
self.__dict__ = self._shared_data # Make it an attribute dictionary
class Singleton(Borg): #Inherits from the Borg class
"""This class now shares all its attributes among its various instances"""
#This essenstially makes the singleton objects an object-oriented global variable
def __init__(self, **kwargs):
Borg.__init__(self)
self._shared_data.update(kwargs) # Update the attribute dictionary by inserting a new key-value pair
def __str__(self):
return str(self._shared_data) # Returns the attribute dictionary for printing
#Let's create a singleton object and add our first acronym
x = Singleton(HTTP="Hyper Text Transfer Protocol")
# Print the object
print(x)
#Let's create another singleton object and if it refers to the same attribute dictionary by adding another acronym.
y = Singleton(SNMP="Simple Network Management Protocol")
# Print the object
print(y)
#Builder
Builders are good at solving problems with building a complex object using an excessive number of constructors.
Solution:
Director
Abstract Builder: interfaces
Concrete Builder: implements the interfaces
Product: object being built
class Director():
"""Director"""
def __init__(self, builder):
self._builder = builder
def construct_car(self):
self._builder.create_new_car()
self._builder.add_model()
self._builder.add_tires()
self._builder.add_engine()
def get_car(self):
return self._builder.car
class Builder():
"""Abstract Builder"""
def __init__(self):
self.car = None
def create_new_car(self):
self.car = Car()
class SkyLarkBuilder(Builder):
"""Concrete Builder --> provides parts and tools to work on the parts """
def add_model(self):
self.car.model = "Skylark"
def add_tires(self):
self.car.tires = "Regular tires"
def add_engine(self):
self.car.engine = "Turbo engine"
class Car():
"""Product"""
def __init__(self):
self.model = None
self.tires = None
self.engine = None
def __str__(self):
return '{} | {} | {}'.format(self.model, self.tires, self.engine)
builder = SkyLarkBuilder()
director = Director(builder)
director.construct_car()
car = director.get_car()
print(car)
#Prototype
Prototypes work well in creating multiple identical items.
import copy
class Prototype:
def __init__(self):
self._objects = {}
def register_object(self, name, obj):
"""Register an object"""
self._objects[name] = obj
def unregister_object(self, name):
"""Unregister an object"""
del self._objects[name]
def clone(self, name, **attr):
"""Clone a registered object and update its attributes"""
obj = copy.deepcopy(self._objects.get(name))
obj.__dict__.update(attr)
return obj
class Car:
def __init__(self):
self.name = "Skylark"
self.color = "Red"
self.options = "Ex"
def __str__(self):
return '{} | {} | {}'.format(self.name, self.color, self.options)
c = Car()
prototype = Prototype()
prototype.register_object('skylark',c)
c1 = prototype.clone('skylark')
print(c1)