Design Pattern
Singleton Design Pattern
Singleton provides you with a mechanism to have one, and only one, object of a given type and provides a global point of access.
这个模式的要点在于只创建一个实例,并为此提供全局接口。
Hence, Singletons are typically used in cases such as logging or database operations, printer spoolers, and many others, where there is a need to have only one instance that is available across the application to avoid conflicting requests on the same resource. For example, we may want to use one database object to perform operations on the DB to maintain data consistency or one object of the logging class across multiple services to dump log messages in a particular log file sequentially.
最容易想到的用途应该是数据库登录。
In brief, the intentions of the Singleton design pattern are as follows:
- Ensuring that one and only one object of the class gets created
- Providing an access point for an object that is global to the program
- Controlling concurrent access to resources that are shared
简单来说,这种模式的特点在于这几个方面:(1)保证只有一个实例被创建;(2)提供全局接口;(3)控制对资源的多线程访问
A simple way of implementing Singleton is by making the constructor private and creating a static method that does the object initialization. This way, one object gets created on the first call and the class returns the same object thereafter.
class Singleton(object):
def __new__(cls):
if not hasattr(cls, 'instance'):
cls.instance = super(Singleton, cls).__new__(cls)
return cls.instance
s = Singleton()
print("Object created", s)
s1 = Singleton()
print("Object created", s1)
Lazy instantiation in the Singleton pattern
Lazy instantiation makes sure that the object gets created when it’s actually needed. Consider lazy instantiation as the way to work with reduced resources and create them only when needed.
class Singleton:
__instance = None
def __init__(self):
if not Singleton.__instance:
print(" __init__ method called..")
else:
print("Instance already created:", self.getInstance())
@classmethod
def getInstance(cls):
if not cls.__instance:
cls.__instance = Singleton()
return cls.__instance
s = Singleton() ## class initialized, but object not created
print("Object created", Singleton.getInstance()) ## Gets created here
s1 = Singleton() ## instance already created
The Monostate Singleton pattern
As the concept is based on all objects sharing the same state, it is also known as the Monostate pattern.
class Borg:
__shared_state = {"1":"2"}
def __init__(self):
self.x = 1
self.__dict__ = self.__shared_state
pass
b = Borg()
b1 = Borg()
b.x = 4
print("Borg Object 'b': ", b) ## b and b1 are distinct objects
print("Borg Object 'b1': ", b1)
print("Object State 'b':", b.__dict__) ## b and b1 share same state
print("Object State 'b1':", b1.__dict__)
The Factory Pattern – Building Factories to Create Objects
In object-oriented programming, the term factory means a class that is responsible for creating objects of other types. Typically, the class that acts as a factory has an object and methods associated with it. The client calls this method with certain parameters; objects of desired types are created in turn and returned to the client by the factory.
from abc import ABCMeta, abstractmethod
class Animal(metaclass = ABCMeta):
@abstractmethod
def do_say(self):
pass
class Dog(Animal):
def do_say(self):
print("Bhow Bhow!!")
class Cat(Animal):
def do_say(self):
print("Meow Meow!!")
## forest factory defined
class ForestFactory(object):
def make_sound(self, object_type):
return eval(object_type)().do_say()
## client code
if __name__ == '__main__':
ff = ForestFactory()
animal = input("Which animal should make_sound Dog or Cat?")
ff.make_sound(animal)
The Façade Pattern – Being Adaptive with Façade
Understanding Structural design patterns
The following points will help us understand more about Structural patterns:
- Structural patterns describe how objects and classes can be combined to form larger structures.
- Structural patterns can be thought of as design patterns that ease the design by identifying simpler ways to realize or demonstrate relationships between entities. Entities mean objects or classes in the object-oriented world.
- While the Class patterns describe abstraction with the help of inheritance and provide a more useful program interface, Object patterns describe how objects can be associated and composed to form larger objects. Structural patterns are a combination of Class and Object patterns.
Understanding the Façade design pattern
Façade hides the complexities of the internal system and provides an interface to the client that can access the system in a very simplified way.
Consider the example of a storekeeper. Now, when you, as a customer, visit a store to buy certain items, you’re not aware of the layout of the store. You typically approach the storekeeper, who is well aware of the store system. Based on your requirements, the storekeeper picks up items and hands them over to you. Isn’t this easy? The customer need not know how the store looks and s/he gets the stuff done through a simple interface, the storekeeper.
An example
As discussed earlier, the Façade class simplifies the interface for the client. In this case, EventManager acts as a façade and simplifies the work for You. Façade talks to the subsystems and does all the booking and preparations for the marriage on your behalf.
class Hotelier(object):
def __init__(self):
print("Arranging the Hotel for Marriage? --")
def __isAvailable(self):
print("Is the Hotel free for the event on given day?")
return True
def bookHotel(self):
if self.__isAvailable():
print("Registered the Booking\n\n")
class Florist(object):
def __init__(self):
print("Flower Decorations for the Event? --")
def setFlowerRequirements(self):
print("Carnations, Roses and Lilies would be used for Decorations\n\n")
class Caterer(object):
def __init__(self):
print("Food Arrangements for the Event --")
def setCuisine(self):
print("Chinese & Continental Cuisine to be served\n\n")
class Musician(object):
def __init__(self):
print("Musical Arrangements for the Marriage --")
def setMusicType(self):
print("Jazz and Classical will be played\n\n")
class EventManager(object):
def __init__(self):
print("Event Manager:: Let me talk to the folks\n")
def arrange(self):
self.hotelier = Hotelier()
self.hotelier.bookHotel()
self.florist = Florist()
self.florist.setFlowerRequirements()
self.caterer = Caterer()
self.caterer.setCuisine()
self.musician = Musician()
self.musician.setMusicType()
class You(object):
def __init__(self):
print("You:: Whoa! Marriage Arrangements??!!!")
def askEventManager(self):
print("You:: Let's Contact the Event Manager\n\n")
em = EventManager()
em.arrange()
def __del__(self):
print("You:: Thanks to Event Manager, all preparations done! Phew!")
you = You()
you.askEventManager()
The Proxy Pattern – Controlling Object Access
Proxy, in general terms, is a system that intermediates between the seeker and provider. Seeker is the one that makes the request, and provider delivers the resources in response to the request. In the web world, we can relate this to a proxy server. The clients (users in the World Wide Web), when they make a request to the website, first connect to a proxy server asking for resources such as a web page. The proxy server internally evaluates this request, sends it to an appropriate server, and gets back the response, which is then delivered to the client. Thus, a proxy server encapsulates requests, enables privacy, and works well in distributed architectures.
** An example**
Consider the example of an Actor and his Agent. When production houses want to approach an Actor for a movie, typically, they talk to the Agent and not to the Actor directly. Based on the schedule of the Actor and other engagements, the Agent gets back to the production house on the availability and interest in working in the movie. The Agent acts as a Proxy that handles all the scheduling & payments for the Actor.
class Actor(object):
def __init__(self):
self.isBusy = False
def occupied(self):
self.isBusy = True
print(type(self).__name__ , "is occupied with current movie")
def available(self):
self.isBusy = False
print(type(self).__name__ , "is free for the movie")
def getStatus(self):
return self.isBusy
class Agent(object):
def __init__(self):
self.principal = None
def work(self):
self.actor = Actor()
if self.actor.getStatus():
self.actor.occupied()
else:
self.actor.available()
if __name__ == '__main__':
r = Agent()
r.work()
The Observer Pattern – Keeping Objects in the Know
In the Observer design pattern, an object (Subject) maintains a list of dependents (Observers) so that the Subject can notify all the Observers about the changes that it undergoes using any of the methods defined by the Observer.
class Subject:
def __init__(self):
self.__observers = []
def register(self, observer):
self.__observers.append(observer)
def notifyAll(self, *args, **kwargs):
for observer in self.__observers:
observer.notify(self, *args, **kwargs)
class Observer1:
def __init__(self, subject):
subject.register(self)
def notify(self, subject, *args):
print(type(self).__name__,':: Got', args, 'From', subject)
class Observer2:
def __init__(self, subject):
subject.register(self)
def notify(self, subject, *args):
print(type(self).__name__, ':: Got', args, 'From', subject)
subject = Subject()
observer1 = Observer1(subject)
observer2 = Observer2(subject)
subject.notifyAll('notification')
# coding = UTF-8
class NewsPublisher:
def __init__(self):
self.__subscribers = []
self.__latestNews = None
def attach(self, subscriber):
self.__subscribers.append(subscriber)
def detach(self):
return self.__subscribers.pop()
def subscribers(self):
return [type(x).__name__ for x in self.__subscribers]
def notifySubscribers(self):
for sub in self.__subscribers:
sub.update()
def addNews(self, news):
self.__latestNews = news
def getNews(self):
return "Got News:", self.__latestNews
from abc import ABCMeta, abstractmethod
class Subscriber(metaclass=ABCMeta):
@abstractmethod
def update(self):
pass
class SMSSubscriber:
def __init__(self, publisher):
self.publisher = publisher
self.publisher.attach(self)
def update(self):
print(type(self).__name__, self.publisher.getNews())
class EmailSubscriber:
def __init__(self, publisher):
self.publisher = publisher
self.publisher.attach(self)
def update(self):
print(type(self).__name__, self.publisher.getNews())
class AnyOtherSubscriber:
def __init__(self, publisher):
self.publisher = publisher
self.publisher.attach(self)
def update(self):
print(type(self).__name__, self.publisher.getNews())
if __name__ == '__main__':
news_publisher = NewsPublisher()
for Subscribers in [SMSSubscriber, EmailSubscriber, AnyOtherSubscriber]:
Subscribers(news_publisher)
print("\nSubscribers:", news_publisher.subscribers())
news_publisher.addNews('Hello World!')
news_publisher.notifySubscribers()
print("\nDetached:", type(news_publisher.detach()).__name__)
print("\nSubscribers:", news_publisher.subscribers())
news_publisher.addNews('My second news!')
news_publisher.notifySubscribers()
The Command Pattern – Encapsulating Invocation
The Command pattern is a behavioral design pattern in which an object is used to encapsulate all the information needed to perform an action or trigger an event at a later time.
class Wizard():
def __init__(self, src, rootdir):
self.choices = []
self.rootdir = rootdir
self.src = src
def preferences(self, command):
self.choices.append(command)
def execute(self):
for choice in self.choices:
if list(choice.values())[0]:
print("Copying binaries --", self.src, " to ", self.rootdir)
else:
print("No Operation")
def rollback(self):
print("Deleting the unwanted..", self.rootdir)
if __name__ == '__main__':
## Client code
wizard = Wizard('python3.5.gzip', '/usr/bin/')
## Steps for installation. ## Users chooses to install Python only
wizard.preferences({'python':True})
wizard.preferences({'java':False})
wizard.execute()
from abc import ABCMeta, abstractmethod
class Command(metaclass=ABCMeta):
def __init__(self, recv):
self.recv = recv
def execute(self):
pass
class ConcreteCommand(Command):
def __init__(self, recv):
self.recv = recv
def execute(self):
self.recv.action()
class Receiver:
def action(self):
print("Receiver Action")
class Invoker:
def command(self, cmd):
self.cmd = cmd
def execute(self):
self.cmd.execute()
if __name__ == '__main__':
recv = Receiver()
cmd = ConcreteCommand(recv)
invoker = Invoker()
invoker.command(cmd)
invoker.execute()
from abc import ABCMeta, abstractmethod
class Order(metaclass=ABCMeta):
@abstractmethod
def execute(self):
pass
class StockTrade:
def buy(self):
print("You will buy stocks")
def sell(self):
print("You will sell stocks")
class Agent:
def __init__(self):
self.__orderQueue = []
def placeOrder(self, order):
self.__orderQueue.append(order)
order.execute()
class BuyStockOrder(Order):
def __init__(self, stock):
self.stock = stock
def execute(self):
self.stock.buy()
class SellStockOrder(Order):
def __init__(self, stock):
self.stock = stock
def execute(self):
self.stock.sell()
if __name__ == '__main__':
#Client
stock = StockTrade()
buyStock = BuyStockOrder(stock)
sellStock = SellStockOrder(stock)
#Invoker
agent = Agent()
agent.placeOrder(buyStock)
agent.placeOrder(sellStock)
The Template Method Pattern – Encapsulating Algorithm
The Template Method pattern is a behavioral design pattern that defines the program skeleton or an algorithm in a method called the Template Method. It is important to note that the change in the steps (as done by the subclasses) don’t impact the original algorithm’s structure. Thus, the facility of overriding by subclasses in the Template Method pattern allows the creation of different behaviors or algorithms.
from abc import ABCMeta, abstractmethod
class AbstractClass(metaclass=ABCMeta):
def __init__(self):
pass
@abstractmethod
def operation1(self):
pass
@abstractmethod
def operation2(self):
pass
def template_method(self):
print("Defining the Algorithm. Operation1 follows Operation2")
self.operation2()
self.operation1()
class ConcreteClass(AbstractClass):
def operation1(self):
print("My Concrete Operation1")
def operation2(self):
print("Operation 2 remains same")
class Client:
def main(self):
self.concreate = ConcreteClass()
self.concreate.template_method()
client = Client()
client.main()
from abc import ABCMeta, abstractmethod
class Compiler(metaclass=ABCMeta):
@abstractmethod
def collectSource(self):
pass
@abstractmethod
def compileToObject(self):
pass
@abstractmethod
def run(self):
pass
def compileAndRun(self):
self.collectSource()
self.compileToObject()
self.run()
class iOSCompiler(Compiler):
def collectSource(self):
print("Collecting Swift Source Code")
def compileToObject(self):
print("Compiling Swift code to LLVM bitcode")
def run(self):
print("Program runing on runtime environment")
iOS = iOSCompiler()
iOS.compileAndRun()
from abc import abstractmethod, ABCMeta
class Trip(metaclass=ABCMeta):
@abstractmethod
def setTransport(self):
pass
@abstractmethod
def day1(self):
pass
@abstractmethod
def day2(self):
pass
@abstractmethod
def day3(self):
pass
@abstractmethod
def returnHome(self):
pass
def itinerary(self):
self.setTransport()
self.day1()
self.day2()
self.day3()
self.returnHome()
class VeniceTrip(Trip):
def setTransport(self):
print("Take a boat and find your way in the Grand Canal")
def day1(self):
print("Visit St Mark's Basilica in St Mark's Square")
def day2(self):
print("Appreciate Doge's Palace")
def day3(self):
print("Enjoy the food near the Rialto Bridge")
def returnHome(self):
print("Get souvenirs for friends and get back")
class MaldivesTrip(Trip):
def setTransport(self):
print("On foot, on any island, Wow!")
def day1(self):
print("Enjoy the marine life of Banana Reef")
def day2(self):
print("Go for the water sports and snorkelling")
def day3(self):
print("Relax on the beach and enjoy the sun")
def returnHome(self):
print("Dont feel like leaving the beach..")
class TravelAgency:
def arrange_trip(self):
choice = input("What kind of place you'd like to go historical or to a beach?")
if choice == 'historical':
self.venice = VeniceTrip()
self.venice.itinerary()
if choice == 'beach':
self.maldives = MaldivesTrip()
self.maldives.itinerary()
TravelAgency().arrange_trip()
Model-View-Controller – Compound Patterns
This is how the MVC pattern works: the model represents the data and business logic (how information is stored and queried), view is nothing but the representation (how it is presented) of the data, and controller is the glue between the two, the one that directs the model and view to behave in a certain way based on what a user needs. Interestingly, the view and controller are dependent on the model but not the other way round. This is primarily because a user is concerned about the data. Models can be worked with independently and this is the key aspect of the MVC pattern.
The MVC design pattern works with the following terms—Model, View, Controller and the Client:
- Model: This declares a class to store and manipulate data
- View: This declares a class to build user interfaces and data displays
- Controller: This declares a class that connects the model and view
- User: This declares a class that requests for certain results based on certain actions
class Model(object):
def logic(self):
data = 'Got it!'
print("Model: Crunching data as per business logic")
return data
class View(object):
def update(self, data):
print("View: Updating the view with results: ", data)
class Controller(object):
def __init__(self):
self.model = Model()
self.view = View()
def interface(self):
print("Controller: Relayed the Cient asks")
data = self.model.logic()
self.view.update(data)
class Client(object):
print("Client: asks for certain information")
controller = Controller()
controller.interface()
The State Design Pattern
The State design pattern is a Behavioral design pattern, which is also sometimes referred to as an objects for states pattern. In this pattern, an object can encapsulate multiple behaviors based on its internal state.
from abc import abstractmethod, ABCMeta
class State(metaclass=ABCMeta):
@abstractmethod
def Handle(self):
pass
class ConcreteStateB(State):
def Handle(self):
print("ConcreteStateB")
class ConcreteStateA(State):
def Handle(self):
print("ConcreteStateA")
class Context(State):
def __init__(self):
self.state = None
def getState(self):
return self.state
def setState(self, state):
self.state = state
def Handle(self):
self.state.Handle()
context = Context()
stateA = ConcreteStateA()
stateB = ConcreteStateB()
context.setState(stateA)
context.Handle()
from abc import abstractmethod, ABCMeta
class State(metaclass=ABCMeta):
@abstractmethod
def doThis(self):
pass
class StartState (State):
def doThis(self):
print("TV Switching ON..")
class StopState (State):
def doThis(self):
print("TV Switching OFF..")
class TVContext(State):
def __init__(self):
self.state = None
def getState(self):
return self.state
def setState(self, state):
self.state = state
def doThis(self):
self.state.doThis()
context = TVContext()
context.getState()
start = StartState()
stop = StopState()
context.setState(stop)
context.doThis()
class ComputerState(object):
name = "state"
allowed = []
def switch(self, state):
if state.name in self.allowed:
print('Current:',self,' => switched to new state',state.name)
self.__class__ = state
else:
print('Current:',self,' => switching to',state.name,'not possible.')
def __str__(self):
return self.name
class Off(ComputerState):
name = "off"
allowed = ['on']
class On(ComputerState):
name = "on"
allowed = ['off','suspend','hibernate']
class Suspend(ComputerState):
name = "suspend"
allowed = ['on']
class Hibernate(ComputerState):
name = "hibernate"
allowed = ['on']
class Computer(object):
def __init__(self, model='HP'):
self.model = model
self.state = Off()
def change(self, state):
self.state.switch(state)
if __name__ == "__main__":
comp = Computer()
# Switch on
comp.change(On)
# Switch off
comp.change(Off)
# Switch on again
comp.change(On)
# Suspend
comp.change(Suspend)
# Try to hibernate - cannot!
comp.change(Hibernate)
# switch on back
comp.change(On)
# Finally off
comp.change(Off)
网友评论