1. Responsibility chain model
The content of the responsibility chain pattern: multiple objects have the opportunity to process the request, so as to avoid the coupling relationship between the sender and receiver of the request. Connect these objects into a chain and pass the request along the chain until an object processes it. The roles of responsibility chain include abstract handler, concrete handler and client.
from abc import ABCMeta, abstractmethod # Abstract processor class Handler(metaclass=ABCMeta): @abstractmethod def handle_leave(self, day): pass # Specific handler class GeneralManager(Handler): def handle_leave(self, day): if day <= 30: print('Leave granted by the general manager%d' % day) else: print('You can resign!') # Specific handler class DepartmentManager(Handler): def __init__(self): self.next = GeneralManager() def handle_leave(self, day): if day <= 7: print('Leave granted by project director%d' % day) else: print('Insufficient authority of Department Manager') self.next.handle_leave(day) # Specific handler class ProjectDirector(Handler): def __init__(self): self.next = DepartmentManager() def handle_leave(self, day): if day <= 3: print('Leave granted by project director%d' % day) else: print('Insufficient authority of project director') self.next.handle_leave(day) day = 20 p = ProjectDirector() p.handle_leave(day) """ Insufficient authority of project director Insufficient authority of Department Manager Leave granted by the general manager 20 """
Usage scenario: there are multiple objects that can process a request, and the processing of which object is determined by the runtime; Submit a request to one of multiple objects without specifying the recipient. The advantage is to reduce the degree of coupling. One object does not need to know which other object handles its request.
2. Observer mode
Observer mode is widely used, also known as "publish subscribe" mode. It is used to define a one to many dependency between objects. When the state of an object changes, all objects that depend on it are notified and updated automatically. The roles of observer pattern are: abstract topic, concrete topic (publisher), abstract observer and concrete observer (subscriber).
from abc import ABCMeta, abstractmethod # Abstract subscriber class Observer(metaclass=ABCMeta): @abstractmethod def update(self, notice): """ :param notice: Notice Object of class :return: """ pass # Abstract Publisher: it can be an interface. Subclasses do not need to be implemented, so there is no need to define abstract methods! class Notice: def __init__(self): self.observers = [] def attach(self, obs): self.observers.append(obs) def detach(self, obs): self.observers.remove(obs) def notify(self): """ Push :return: """ for obs in self.observers: obs.update(self) # Specific publisher class StaffNotice(Notice): def __init__(self, company_info): super().__init__() # Call the parent class object to declare the observers property self.__company_info = company_info @property def company_info(self): return self.__company_info @company_info.setter def company_info(self, info): self.__company_info = info self.notify() # Specific subscribers class Staff(Observer): def __init__(self): self.company_info = None def update(self, notice): self.company_info = notice.company_info staff_notice = StaffNotice('Initialize company information') staff1 = Staff() staff2 = Staff() staff_notice.attach(staff1) staff_notice.attach(staff2) # print(staff1.company_info) None # print(staff2.company_info) None staff_notice.company_info = 'Holiday notice!' print(staff1.company_info) print(staff2.company_info) staff_notice.detach(staff2) staff_notice.company_info = 'Meeting tomorrow!' print(staff1.company_info) print(staff2.company_info) """ Holiday notice! Holiday notice! Meeting tomorrow! Holiday notice! """
Usage scenario: when an abstract model has two aspects, one of which depends on the other. Encapsulating the two in independent objects so that they can be changed and reused independently; When changing one object requires changing other objects at the same time, we don't know how many objects need to be changed; When an object must notify other objects, it cannot assume who the other objects are. In other words, you don't want these objects to be tightly coupled. Advantages: the abstract coupling between the target and the observer is minimal; Support broadcast communication.
3. Strategy mode
Define algorithms, encapsulate them, and make them interchangeable. This pattern allows the algorithm to vary independently of the customers using it. Roles include: Abstract strategy, concrete strategy and context.
from abc import abstractmethod, ABCMeta from datetime import datetime # Abstract strategy class Strategy(metaclass=ABCMeta): @abstractmethod def execute(self, data): pass # Specific strategies class FastStrategy(Strategy): def execute(self, data): print("Use faster policy processing%s" % data) # Specific strategies class SlowStrategy(Strategy): def execute(self, data): print("Use slower policy processing%s" % data) # context class Context: def __init__(self, strategy, data): self.data = data self.strategy = strategy # You can define things that users don't know self.date = datetime.now() def set_strategy(self, strategy): self.strategy = strategy def do_strategy(self): self.strategy.execute(self.data) data = "Hello!" # Use faster policy processing fast_strategy = FastStrategy() context = Context(fast_strategy, data) context.do_strategy() # Use slower policy processing slow_strategy = SlowStrategy() context = Context(slow_strategy, data) context.do_strategy() """ Use faster policy processing Hello! Use slower policy processing Hello! """
Advantages: some reusable algorithms and behaviors are defined; Some conditional statements are eliminated; Different implementations of the same behavior can be provided; Disadvantages: customers must understand different strategies.
4. Template method mode
Content: define the algorithm skeleton in an operation and delay some steps to subclasses. Template method allows subclasses to redefine some specific steps of an algorithm without changing the structure of the algorithm. Using template method requires two roles: abstract class and concrete class. Abstract classes are used to define abstract classes (hook operations) and implement a template method as the skeleton of the algorithm. The role of concrete classes is to realize atomic operations.
from abc import ABCMeta, abstractmethod from time import sleep # abstract class class Window(metaclass=ABCMeta): @abstractmethod def start(self): # Atomic operation / hook operation pass @abstractmethod def repaint(self): # Atomic operation / hook operation pass @abstractmethod def stop(self): # Atomic operation / hook operation pass def run(self): """ Template method(Specific method),This big logic doesn't need to be written by yourself :return: """ self.start() while True: try: self.repaint() sleep(1) except KeyboardInterrupt: break self.stop() # concrete class class MyWindow(Window): def __init__(self, msg): self.msg = msg def start(self): print('The window starts running!') def stop(self): print('Window stop!') def repaint(self): print(self.msg) MyWindow("Hello...").run()
Applicable scenarios of template method: implement the invariant part of an algorithm at one time, and the public behaviors in each subclass should be extracted and concentrated in a common parent class to avoid code duplication; Control subclass extension.