Design mode and python implementation

Keywords: PHP shell Mobile Python Programming

Design Patterns and Python Implementation

 

What is the design pattern?

Christopher Alexander: "Each pattern describes a problem that is recurring around us and the core of the solution to that problem.This allows you to use the program again and again without having to repeat your work."

Design patterns are summarized and optimized reusable solutions to some programming problems that we often encounter.A design pattern does not act directly on our code like a class or library.Conversely, design patterns are more advanced and are a method template that must be implemented in specific situations.Design patterns do not bind specific programming languages.A good design pattern should be implemented in most programming languages (depending on language characteristics, if not all).Most importantly, design patterns are also a double-edged sword, which can cause disasters and endless troubles if used in inappropriate situations.However, if design patterns are used in the right place at the right time, it will be your savior.

At first, you'll think of a "pattern" as a particularly smart way to solve a particular type of problem.That's right. It does look like the most versatile and flexible solution that comes from seeing things from different perspectives and working together with a lot of people.Maybe you've seen or solved these problems before, but your solution is probably not as complete as the pattern.

Although called design patterns, they are not closely related to the design domain.Design patterns are different from traditional analysis, design and implementation. In fact, design patterns root a complete idea in the program, so it may appear in the analysis stage or higher design stage.It's interesting because the design pattern is specific to program code, so you might think that it won't appear before the implementation phase (in fact, you're not aware you're using the specific design pattern until you enter the implementation phase).

You can understand patterns through the basic concepts of programming: adding an abstraction layer.An abstract thing is to isolate any specific details in order to separate those unchanged core parts from other details.When you find that parts of your program are often changed for some reason, and you don't want those parts to cause other parts to change, you need to think about design methods that won't change.Doing so not only makes the code more maintainable, but also makes it easier to understand, reducing development costs.

Three basic design patterns:

  1. Create patterns, provide instantiation methods, and provide appropriate object creation methods for the appropriate situation.
  2. Structured patterns, often used to handle relationships between entities, allow them to work together better.
  3. Behavior patterns are used to build communication between different entities, providing easier and more flexible methods of communication between entities.

Six Principles of Design Mode

  • Open and Close Principle: A software entity such as classes, modules, and functions should be open to extensions and closed to modifications.That is, the software entity should expand as far as possible without modifying the original code.
  • Liskov Replacement Principle: All objects that reference a base class (parent class) must be able to use its subclasses transparently.
  • Dependency Inversion Principle: High-level modules should not depend on low-level modules, and both should depend on their abstraction; abstraction should not depend on details; and detail should depend on abstraction.In other words, program interfaces, not implementations.
  • Interface Isolation Principle: Use multiple specialized interfaces instead of a single overall interface, that is, clients should not rely on interfaces that they do not need.
  • Dimitt's rule: A software entity should interact with as few other entities as possible.
  • Single Responsibility Principle: Do not have more than one reason for a class change.In general, a class is responsible for only one responsibility.(

Interface

Interface: A special class that declares several methods that must be implemented by a class that inherits the interface.
Role: Limits the name and invocation of methods of classes that inherit interfaces; hides the internal implementation of classes.

An interface is an abstract base class (parent class), and a class that restricts its inheritance must implement some of the methods defined in the interface.

Python uses ABCMeta, abstractmethod's Abstract class, and abstract method to implement the function of the interface.Interface class defines a method, which is not implemented specifically. Restriction subclasses must have this method.Implement specific functionality in interface subclasses.

# Using abstract classes and methods for abstraction
from abc import ABCMeta
from abc import abstractmethod  # Import abstract methods

class Father(metaclass=ABCMeta):  # Create abstract classes
    
    @abstractmethod
    def f1(self):
        pass

    @abstractmethod
    def f2(self):
        pass

class F1(Father):
    def f1(self):
        pass

    def f2(self):
        pass

    def f3(self):
        pass

obj = F1()
class Interface:
    def method(self, arg):
        raise NotImplementedError
Error Definition Interface

Creative mode

1. Simple Factory Mode

Content: Instead of exposing the implementation details of object creation directly to the client, an instance of the product class is created through a factory class.

Roles:

  • Factory Role (Creator)
  • Abstract Product Role
  • Specific Product Role

Advantage:

  • Hide implementation details of object creation
  • Client does not need to modify code

Disadvantages:

  • Violating the single responsibility principle, the creation logic is federated into one factory class
  • When adding a new product, the factory class code needs to be modified, which violates the open and close principle
from abc import abstractmethod, ABCMeta


class Payment(metaclass=ABCMeta):
    @abstractmethod
    def pay(self, money):
        pass


class Alipay(Payment):
    def __init__(self, enable_yuebao=False):
        self.enable_yuebao = enable_yuebao

    def pay(self, money):
        if self.enable_yuebao:
            print("Payment policy%s element" % money)
        else:
            print("Alipay Payment%s element" % money)


class ApplePay(Payment):
    def pay(self, money):
        print("Apple Payment%s element" % money)


class PaymentFactory:
    def create_payment(self, method):
        if method == "alipay":
            return Alipay()
        elif method == 'yuebao':
            return Alipay(enable_yuebao=True)
        elif method == "applepay":
            return ApplePay()
        else:
            raise NameError(method)


f = PaymentFactory()
p = f.create_payment("yuebao")
p.pay(100)
PaymentFactory Simple Factory

2. Factory Method

Content: Define an interface (factory interface) for creating objects so that subclasses decide which product class to instantiate.

Roles:

  • Abstract Factory Role (Creator)
  • Specific Factory Role (Concrete Creator)
  • Abstract Product Role
  • Specific Product Role

The factory method mode corresponds to a specific factory for each specific product compared to the simple factory mode.

Scenarios applicable:

  • When many, many complex objects need to be produced.
  • When coupling needs to be reduced.
  • When the product type in the system needs to be expanded frequently.

Advantage:

  • Each specific product corresponds to a specific factory class, and there is no need to modify the factory class code
  • Hide implementation details of object creation

Disadvantages:

  • For each additional specific product class, a corresponding specific factory class must be added

from abc import abstractmethod, ABCMeta


class Payment(metaclass=ABCMeta):
    @abstractmethod
    def pay(self, money):
        pass


class Alipay(Payment):
    def pay(self, money):
        print("Alipay Payment%s element" % money)


class ApplePay(Payment):
    def pay(self, money):
        print("Apple Payment%s element" % money)


class PaymentFactory(metaclass=ABCMeta):
    @abstractmethod
    def create_payment(self):
        pass


class AlipayFactory(PaymentFactory):
    def create_payment(self):
        return Alipay()


class ApplePayFactory(PaymentFactory):
    def create_payment(self):
        return ApplePay()


af = AlipayFactory()
ali = af.create_payment()
ali.pay(120)
Factory method

3. Abstract Factory Method

Content: Define a factory class interface that allows a factory subclass to create a series of related or interdependent objects.
Example: To produce a mobile phone, there are three kinds of objects: the mobile phone shell, CPU and operating system. Each kind of object has different kinds.For each specific factory, three objects are needed to produce a mobile phone.
Roles:

  • Abstract Factory Role (Creator)
  • Specific Factory Role (Concrete Creator)
  • Abstract Product Role
  • Specific Product Role
  • Client

Each specific factory in the abstract factory model produces a set of products compared to the factory method model.
Scenarios applicable:

  • When the system is to be independent of the creation and combination of products
  • Emphasize the design of a series of related product objects for joint use
  • Provides a product class library to hide specific implementations of a product

Advantage:

  • Separate the client from the specific implementation of the class
  • Each factory creates a complete product line, making it easy to exchange product lines
  • Favor product consistency (i.e. constraints between products)

Disadvantages:

  • It is difficult to support a new kind of (abstract) product

from abc import abstractmethod, ABCMeta


# ------Abstract product------
class PhoneShell(metaclass=ABCMeta):
    @abstractmethod
    def show_shell(self):
        pass


class CPU(metaclass=ABCMeta):
    @abstractmethod
    def show_cpu(self):
        pass


class OS(metaclass=ABCMeta):
    @abstractmethod
    def show_os(self):
        pass


# ------Abstract factory------

class PhoneFactory(metaclass=ABCMeta):
    @abstractmethod
    def make_shell(self):
        pass

    @abstractmethod
    def make_cpu(self):
        pass

    @abstractmethod
    def make_os(self):
        pass


# ------Specific products------

class SmallShell(PhoneShell):
    def show_shell(self):
        print("Small mobile phone shell")


class BigShell(PhoneShell):
    def show_shell(self):
        print("Large mobile phone shell")


class AppleShell(PhoneShell):
    def show_shell(self):
        print("Apple mobile phone shell")


class SnapDragonCPU(CPU):
    def show_cpu(self):
        print("snapdragon CPU")


class MediaTekCPU(CPU):
    def show_cpu(self):
        print("Associative Family CPU")


class AppleCPU(CPU):
    def show_cpu(self):
        print("Apple CPU")


class Android(OS):
    def show_os(self):
        print("Android system")


class IOS(OS):
    def show_os(self):
        print("iOS system")


# ------Specific factories------

class MiFactory(PhoneFactory):
    def make_cpu(self):
        return SnapDragonCPU()

    def make_os(self):
        return Android()

    def make_shell(self):
        return BigShell()


class HuaweiFactory(PhoneFactory):
    def make_cpu(self):
        return MediaTekCPU()

    def make_os(self):
        return Android()

    def make_shell(self):
        return SmallShell()


class IPhoneFactory(PhoneFactory):
    def make_cpu(self):
        return AppleCPU()

    def make_os(self):
        return IOS()

    def make_shell(self):
        return AppleShell()


# ------Client------

class Phone:
    def __init__(self, cpu, os, shell):
        self.cpu = cpu
        self.os = os
        self.shell = shell

    def show_info(self):
        print("Text message:")
        self.cpu.show_cpu()
        self.os.show_os()
        self.shell.show_shell()


def make_phone(factory):
    cpu = factory.make_cpu()
    os = factory.make_os()
    shell = factory.make_shell()
    return Phone(cpu, os, shell)


p1 = make_phone(HuaweiFactory())
p1.show_info()
Abstract factory

4. Builder Mode

Content: Separates the construction of a complex object from its representation so that the same construction process can create different representations.
Roles:

  • Builder
  • Concrete Builder
  • Director
  • Product

Builder mode is similar to abstract factory mode and is used to create complex objects.The main difference is that the builder pattern focuses on building a complex object step by step, while the abstract factory pattern focuses on a number of series of product objects.

Scenarios applicable:

  • When the algorithm for creating a complex object (Director) should be independent of its components and how they are assembled (Builder)
  • When the construction process allows different representations of the constructed object (different Builder s).

Advantage:

  • Hide the internal structure and assembly process of a product
  • Separate construction code from representation code
  • More fine-grained control of the construction process is possible

from abc import abstractmethod, ABCMeta

# ------product------

class Player:
    def __init__(self, face=None, body=None, arm=None, leg=None):
        self.face = face
        self.arm = arm
        self.leg = leg
        self.body = body

    def __str__(self):
        return "%s, %s, %s, %s" % (self.face, self.arm, self.body, self.leg)


# ------Builder------

class PlayerBuilder(metaclass=ABCMeta):
    @abstractmethod
    def build_face(self):
        pass

    @abstractmethod
    def build_arm(self):
        pass

    @abstractmethod
    def build_leg(self):
        pass

    @abstractmethod
    def build_body(self):
        pass

    @abstractmethod
    def get_player(self):
        pass


class BeautifulWomanBuilder(PlayerBuilder):
    def __init__(self):
        self.player = Player()

    def build_face(self):
        self.player.face = "Pretty Face"

    def build_arm(self):
        self.player.arm = "Thin arm"

    def build_body(self):
        self.player.body = "slender waist"

    def build_leg(self):
        self.player.leg = "Long legged"

    def get_player(self):
        return self.player


class PlayerDirector:
    def build_player(self, builder):
        builder.build_body()
        builder.build_arm()
        builder.build_leg()
        builder.build_face()
        return builder.get_player()


director = PlayerDirector()
builder = BeautifulWomanBuilder()
p = director.build_player(builder)
print(p)
Builder pattern

5. Singleton

Content: Ensure that a class has only one instance and provide a global access point to access it.
Roles:

Scenarios applicable

Advantage:

Concepts similar to singleton mode functionality: global variables, static variables (methods)

Realization:

class Singleton(object):
    def __new__(cls, *args, **kw):
        if not hasattr(cls, '_instance'):
            cls._instance = super(Singleton, cls).__new__(cls, )
        return cls._instance


class MyClass(Singleton):
    a = 1

    def __init__(self, name):
        self.name = name


one = MyClass('egon')
two = MyClass('alex')

print(id(one))
print(id(two))
print(one == two)
print(one is two)
1. Using the u new_u method
def singleton(cls, *args, **kw):
    instances = {}

    def get_instance():
        if cls not in instances:
            instances[cls] = cls(*args, **kw)
        return instances[cls]

    return get_instance


@singleton
class MyClass2:
    a = 1


one = MyClass2()
two = MyClass2()

print(id(one))  # 31495472
print(id(two))  # 31495472
print(one == two)
print(one is two)
2. Decorator methods
# Python The module is a natural singleton pattern.
# module_name.py
class MySingleton(object):
    def foo(self):
        print('danli')

my_singleton = MySingleton()

# to use
from .module_name import my_singleton
my_singleton.foo()
print(id(my_singleton))

from .module_name import my_singleton
my_singleton.foo()
print(id(my_singleton))
3. import method
class Singleton(type):
    _instances = {}

    def __call__(cls, *args, **kwargs):
        if cls not in cls._instances:
            cls._instances[cls] = super(Singleton, cls).__call__(*args, **kwargs)
        return cls._instances[cls]


# Python2
# class MyClass:
#     __metaclass__ = Singleton


# Python3
class MyClass(metaclass=Singleton):
    pass


one = MyClass()
two = MyClass()

print(id(one))
print(id(two))
print(one == two)
print(one is two)
4. Use metaclass

6. Prototype

Content: Specify the kind of objects created with prototype instances, and create new objects by copying them.

Use scenarios:

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 inner attributes dictionary"""
        obj = copy.deepcopy(self._objects.get(name))
        obj.__dict__.update(attr)
        return obj


def main():
    class A:
        def __str__(self):
            return "I am A"

    a = A()
    prototype = Prototype()
    prototype.register_object('a', a)
    b = prototype.clone('a', a=1, b=2, c=3)

    print(a)
    print(b.a, b.b, b.c)


if __name__ == '__main__':
    main()
Prototype mode

Creative Mode Summary

Designs using abstract factories, prototypes, or builders are even more flexible than those using factory methods, but they are also more complex.Typically, design begins with a Factory Method.And when designers find that they need more flexibility, they think about other creation models.When you weigh design criteria against each other, understanding multiple patterns can give you more choices.

Creative Patterns Dependent on Inheritance: Factory Method Patterns

Creative Patterns Dependent on Combination: Abstract Factory Patterns, Creator Patterns

Structural patterns

1. Adapter mode (Adapter Class/Object)

Content: Convert the interface of one class to another that the client wants.Adapter mode allows classes that would otherwise not work together due to incompatible interfaces to work together.
Roles:

Two implementations:

Scenarios applicable:

Class adapter:

Object Adapter:

 

 

from abc import abstractmethod, ABCMeta


class Payment(metaclass=ABCMeta):
    @abstractmethod
    def pay(self, money):
        raise NotImplementedError


class Alipay(Payment):
    def pay(self, money):
        print("Alipay Payment%s element" % money)


class ApplePay(Payment):
    def pay(self, money):
        print("Apple Payment%s element" % money)


# ------Class to be adapted------

class WechatPay:
    def cost(self, money):
        print("WeChat Payment%s element" % money)


# Class Adapter
class RealWechatPay(WechatPay, Payment):
    def pay(self, money):
        return self.cost(money)


# object adapter

class RealWechatPay2(Payment):
    def __init__(self):
        self.payment = WechatPay()

    def pay(self, money):
        return self.payment.cost(money)


p = RealWechatPay2()
p.pay(111)
Adapter

2. Composite

Content: Groups objects into a tree structure to represent a "part-whole" hierarchy.Combination mode makes the use of individual and combined objects consistent.
Roles:

Scenarios applicable:

Advantage:

Disadvantages:

from abc import abstractmethod, ABCMeta

class Graphic(metaclass=ABCMeta):
    @abstractmethod
    def draw(self):
        pass

    @abstractmethod
    def add(self, graphic):
        pass

    def getchildren(self):
        pass

# Primitives

class Point(Graphic):
    def __init__(self, x, y):
        self.x = x
        self.y = y

    def draw(self):
        print(self)

    def add(self, graphic):
        raise TypeError

    def getchildren(self):
        raise TypeError

    def __str__(self):
        return "spot(%s, %s)" % (self.x, self.y)


class Line(Graphic):
    def __init__(self, p1, p2):
        self.p1 = p1
        self.p2 = p2

    def draw(self):
        print(self)

    def add(self, graphic):
        raise TypeError

    def getchildren(self):
        raise TypeError

    def __str__(self):
        return "line segment[%s, %s]" % (self.p1, self.p2)


class Picture(Graphic):
    def __init__(self):
        self.children = []

    def add(self, graphic):
        self.children.append(graphic)

    def getchildren(self):
        return self.children

    def draw(self):
        print("------Composite Graphics------")
        for g in self.children:
            g.draw()
        print("------END------")


pic1 = Picture()
point = Point(2,3)
pic1.add(point)
pic1.add(Line(Point(1,2), Point(4,5)))
pic1.add(Line(Point(0,1), Point(2,1)))

pic2 = Picture()
pic2.add(Point(-2,-1))
pic2.add(Line(Point(0,0), Point(1,1)))

pic = Picture()
pic.add(pic1)
pic.add(pic2)

pic.draw()
#pic1.draw()
#point.draw()
combination

3. Proxy mode

Content: Provides a proxy for other objects to control access to this object.
Roles:

Scenarios applicable:

Advantage:

from abc import ABCMeta, abstractmethod


class Subject(metaclass=ABCMeta):
    @abstractmethod
    def get_content(self):
        pass

    def set_content(self, content):
        pass


class RealSubject(Subject):
    def __init__(self, filename):
        self.filename = filename
        print("read%s File Content" % filename)
        f = open(filename)
        self.__content = f.read()
        f.close()

    def get_content(self):
        return self.__content

    def set_content(self, content):
        f = open(self.filename, 'w')
        f.write(content)
        self.__content = content
        f.close()


# ---Remote Agent

class ProxyA(Subject):
    def __init__(self, filename):
        self.subj = RealSubject(filename)

    def get_content(self):
        return self.subj.get_content()

    def set_content(self, content):
        return self.subj.set_content(content)


# ---Virtual agent

class ProxyB(Subject):
    def __init__(self, filename):
        self.filename = filename
        self.subj = None

    def get_content(self):
        if not self.subj:
            self.subj = RealSubject(self.filename)
        return self.subj.get_content()


x = ProxyB('abc.txt')
# print(x.get_content())

# ---Protection Agent

class ProxyC(Subject):
    def __init__(self, filename):
        self.subj = RealSubject(filename)

    def get_content(self):
        self.subj.get_content()

    def set_content(self, content):
        raise PermissionError

# filename = "abc.txt"
# username = input()
# if username!="alex":
#     p = ProxyC(filename)
# else:
#     p = ProxyA(filename)
#
# print(p.get_content())
proxy pattern

Behavior patterns

1. Chain of Responsibility

Content: Enables multiple objects to process requests, thereby avoiding coupling between the sender and receiver of the request.Join these objects into a chain and pass the request along the chain until one object processes it.
Roles:

Example:

Scenarios applicable:

Advantage:

Disadvantages:

from abc import ABCMeta, abstractmethod


class Handler(metaclass=ABCMeta):
    @abstractmethod
    def handle_leave(self, day):
        pass


class GeneralManagerHandler(Handler):
    def handle_leave(self, day):
        if day < 10:
            print("General Manager Approval%d Day Holiday" % day)
            return True
        else:
            print("Ha-ha")
            return False


class DepartmentManagerHandler(Handler):
    def __init__(self):
        self.successor = GeneralManagerHandler()

    def handle_leave(self, day):
        if day < 7:
            print("Approval by Department Manager%d Day Holiday" % day)
            return True
        else:
            print("Department manager is not authorized to grant leave")
            return self.successor.handle_leave(day)


class ProjectDirectorHandler(Handler):
    def __init__(self):
        self.successor = DepartmentManagerHandler()

    def handle_leave(self, day):
        if day < 3:
            print("Project Supervisor Approval%d Day Holiday" % day)
            return True
        else:
            print("Project Supervisor Has No Right to Leave")
            return self.successor.handle_leave(day)


day = 11
h = ProjectDirectorHandler()
print(h.handle_leave(day))
Leave process
# --Advanced examples--imitate js event processing
from abc import ABCMeta, abstractmethod

class Handler(metaclass=ABCMeta):
    @abstractmethod
    def add_event(self, func):
        pass

    @abstractmethod
    def handle(self):
        pass


class BodyHandler(Handler):
    def __init__(self):
        self.func = None

    def add_event(self, func):
        self.func = func

    def handle(self):
        if self.func:
            return self.func()
        else:
            print("The last level is reached and cannot be processed")


class ElementHandler(Handler):
    def __init__(self, successor):
        self.func = None
        self.successor = successor

    def add_event(self, func):
        self.func = func

    def handle(self):
        if self.func:
            return self.func()
        else:
            return self.successor.handle()


# Client

# <body><div><a>

body = {'type': 'body', 'name': 'body', 'children': [], 'father': None}

div = {'type': 'div', 'name': 'div', 'children': [], 'father': body}

a = {'type': 'a', 'name': 'a', 'children': [], 'father': div}

body['children'].append(div)
div['children'].append(a)

# print(body)


body['event_handler'] = BodyHandler()
div['event_handler'] = ElementHandler(div['father']['event_handler'])
a['event_handler'] = ElementHandler(a['father']['event_handler'])


def attach_event(element, func):
    element['event_handler'].add_event(func)


# test

def func_a():
    print("This is for a Functions of")


def func_div():
    print("This is for div Functions of")


def func_body():
    print("This is for body Functions of")


attach_event(a, func_a)
attach_event(div, func_div)
attach_event(body, func_body)

a['event_handler'].handle()
Mimic js event handling

2. Iterator mode

Content: Provides a way to access elements in an aggregated object sequentially without exposing its internal representation.

Scenarios applicable:

Implementation method: u iter_u, u next_u

class LinkList:
    """Chain Head Node Preserves Chain List Length"""

    class Node:
        def __init__(self, item=None):
            self.item = item
            self.next = None

    class LinkListIterator:
        def __init__(self, node):
            self.node = node

        def __next__(self):
            if self.node:
                cur_node = self.node
                self.node = cur_node.next
                return cur_node.item
            else:
                raise StopIteration

        def __iter__(self):
            return self

    def __init__(self, iterable=None):
        self.head = LinkList.Node(0)
        self.tail = self.head
        self.extend(iterable)

    def append(self, obj):
        s = LinkList.Node(obj)
        self.tail.next = s
        self.tail = s
        self.head.item += 1

    def extend(self, iterable):
        for obj in iterable:
            self.append(obj)

    def __iter__(self):
        return self.LinkListIterator(self.head.next)

    def __len__(self):
        return self.head.item

    def __str__(self):
        return "<<" + ", ".join(map(str, self)) + ">>"


li = [i for i in range(100)]
lk = LinkList(li)
print(lk)
linked list

3. Observer mode

Content: Defines 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 observer mode is also known as the publish-subscribe mode
Roles:

Scenarios applicable:

Advantage:

Disadvantages:

 

from abc import ABCMeta, abstractmethod


class Observer(metaclass=ABCMeta):
    @abstractmethod
    def update(self, notice):
        pass


class Notice:
    def __init__(self):
        self.observers = []

    def attach(self, obs):
        self.observers.append(obs)

    def detach(self, obs):
        self.observers.remove(obs)
        # obs.company_info=None

    def notify(self):
        for obj in self.observers:
            obj.update(self)


class ManagerNotice(Notice):
    def __init__(self, company_info=None):
        super().__init__()
        self.__company_info = company_info

    def detach(self, obs):
        super().detach(obs)
        obs.company_info = None

    @property
    def company_info(self):
        return self.__company_info

    @company_info.setter
    def company_info(self, info):
        self.__company_info = info
        self.notify()


class Manager(Observer):
    def __init__(self):
        self.company_info = None

    def update(self, noti):
        self.company_info = noti.company_info


notice = ManagerNotice()

alex = Manager()
wusir = Manager()

print(alex.company_info)
print(wusir.company_info)

notice.attach(alex)
notice.attach(wusir)
notice.company_info = "The company is running well"

print(alex.company_info)
print(wusir.company_info)

notice.company_info = "The company is going public"

print(alex.company_info)
print(wusir.company_info)

notice.detach(wusir)

notice.company_info = "The company is going bankrupt. Run fast"

print(alex.company_info)
print(wusir.company_info)

notice.company_info = "The company has gone bankrupt"

print(alex.company_info)
print(wusir.company_info)
Publisher-Subscriber

4. Strategy

Content: Define a series of algorithms, encapsulate them one by one, and make them interchangeable.This mode allows the algorithm to change independently of the users who use it.
Roles:

Scenarios applicable:

Advantage:

Disadvantages:

from abc import ABCMeta, abstractmethod
import random


class Sort(metaclass=ABCMeta):
    @abstractmethod
    def sort(self, data):
        pass


class QuickSort(Sort):
    def quick_sort(self, data, left, right):
        if left < right:
            mid = self.partition(data, left, right)
            self.quick_sort(data, left, mid - 1)
            self.quick_sort(data, mid + 1, right)

    def partition(self, data, left, right):
        tmp = data[left]
        while left < right:
            while left < right and data[right] >= tmp:
                right -= 1
            data[left] = data[right]
            while left < right and data[left] <= tmp:
                left += 1
            data[right] = data[left]
        data[left] = tmp
        return left

    def sort(self, data):
        print("Quick Sort")
        return self.quick_sort(data, 0, len(data) - 1)


class MergeSort(Sort):
    def merge(self, data, low, mid, high):
        i = low
        j = mid + 1
        ltmp = []
        while i <= mid and j <= high:
            if data[i] <= data[j]:
                ltmp.append(data[i])
                i += 1
            else:
                ltmp.append(data[j])
                j += 1

        while i <= mid:
            ltmp.append(data[i])
            i += 1

        while j <= high:
            ltmp.append(data[j])
            j += 1

        data[low:high + 1] = ltmp

    def merge_sort(self, data, low, high):
        if low < high:
            mid = (low + high) // 2
            self.merge_sort(data, low, mid)
            self.merge_sort(data, mid + 1, high)
            self.merge(data, low, mid, high)

    def sort(self, data):
        print("Merge Sort")
        return self.merge_sort(data, 0, len(data) - 1)


class Context:
    def __init__(self, data, strategy=None):
        self.data = data
        self.strategy = strategy

    def set_strategy(self, strategy):
        self.strategy = strategy

    def do_strategy(self):
        if self.strategy:
            self.strategy.sort(self.data)
        else:
            raise TypeError


li = list(range(100000))
random.shuffle(li)

context = Context(li, MergeSort())
context.do_strategy()
# print(context.data)

random.shuffle(context.data)

context.set_strategy(QuickSort())
context.do_strategy()
Policy Mode

5. Template Method

Content: Defines the skeleton of the algorithm in an operation, delaying some steps to subclasses.Template methods allow subclasses to redefine certain steps of an algorithm without changing its structure.
Roles:

Scenarios applicable:

from abc import ABCMeta, abstractmethod


class IOHandler(metaclass=ABCMeta):
    @abstractmethod
    def open(self, name):
        pass

    @abstractmethod
    def deal(self, change):
        pass

    @abstractmethod
    def close(self):
        pass

    def process(self, name, change):
        self.open(name)
        self.deal(change)
        self.close()


class FileHandler(IOHandler):
    def open(self, name):
        self.file = open(name, "w")

    def deal(self, change):
        self.file.write(change)

    def close(self):
        self.file.close()


f = FileHandler()
f.process("abc.txt", "Hello World")
Template Method

Reference:

Twenty-three design patterns and their python implementation - Li Qiongyu

 

 
 
 

Posted by artied on Fri, 02 Aug 2019 19:40:21 -0700