[PYTHON] Design Pattern #Proxy

I practiced design patterns so that I could write code that was conscious of design. Other Design Patterns will be released frequently.

Preface

The primary goal is to understand when, what, and how to use design patterns. (I'm new to Java or a statically typed language, and I don't have a long history of python, so I think there are some things that aren't like Pythonista. If you have any suggestions, please teach me.)

This time, the pattern Proxy related to the structure.

What is Proxy

Prepare a proxy to control instance creation and access restrictions, and have the proxy do the work until it is needed. However, when the agent exceeds the range that can be done, the agent gives the role to the original person.

Overview

This sample program is a "named printer". The Main class creates a class instance (agent) for PrinterProxy. Name the instance "Alice" and display the name. Then rename it to "Bob" and display that name.

By setting or getting the name, an instance (person) of the real Printer class has not been created yet. The PrinterProxy class takes care of setting and getting the name. The PrinterProxy class instantiates the Printer class only when the my_print method is finally called and the actual printing is performed.

An interface called Printable is defined to equate the PrinterProxy class with the Printer class. Here, the sample program is created on the assumption that it takes a long time to instantiate the Printer class. In order to express that it takes time, I call a method called heavy_job from the constructor and earn a few seconds as "heavy processing".

Overall class diagram

クラス図

Sequence Diagram

シーケンス図

printer.py


import sys
import time
from printable import Printable


class Printer(Printable):

    def __init__(self, name):
        self.__name = name
        self.__heavy_job('Printer instance({0})Is being generated'.format(self.__name))

    def set_printer_name(self, name):
        self.__name = name

    def get_printer_name(self):
        return self.__name

    def my_print(self, string):
        print('===' + ' ' + self.__name + ' ' + '===')
        print(string)

    def __heavy_job(self, msg):
        sys.stdout.write(msg)
        for i in range(1, 5):
            try:
                time.sleep(1)
            except InterruptedError:
                pass
            sys.stdout.write('.')
        print('Done.')

The Printer class is a class that represents "the person". I am doing heavy_job as a "heavy job". After that, there are set_printer_name for setting the name, get_printer_name for getting the name, and my_print for displaying the character string. The center of the Proxy pattern is towards the PrinterProxy class.

printable.py


from abc import abstractmethod


class Printable():

    @abstractmethod
    def set_printer_name(self, name):
        pass

    @abstractmethod
    def get_printer_name(self):
        pass

    @abstractmethod
    def my_printer(self, string):
        pass

The Printeable interface is for equating the PrinterProxy class with the Printer class.

printer_proxy.py


from printable import Printable
from printer import Printer


class PrinterProxy(Printable):

    def __init__(self, name):
        self.__name = name
        self.__real = None

    def set_printer_name(self, name):
        if (self.__real is not None):
            self.__real.set_printer_name(name)
        self.__name = name

    def get_printer_name(self):
        return self.__name

    def my_print(self, string):
        self.__realize()
        self.__real.my_print(string)

    def __realize(self):
        if (self.__real is None):
            self.__real = Printer(self.__name)

The PrinterProxy class acts as an agent. Implements the Printable interface. The name field is for holding the name, and the real field is for holding the "person".

In the constructor, set the name. The set_printer_name method sets a new name. If real is not None, set the name for the person as well. However, if real is None, it returns a value in the PrinterProxy name field.

Since the my_print method is a process outside the scope of this agent, call the realize method to generate the "person". After executing the realize method, the real field holds the person, so call real.print. This is "delegation".

** No matter how many times you call set_printer_name or get_printer_name, the Printer will not be instantiated. No instance of Printer is created. ** A Printer instance is created only when the "person" is needed. (PrinterProxy users do not know at all whether the person has been generated, and there is no need to worry about it.)

The realize method creates an instance of Printer if the real field is None. If the real field is not None, do nothing.

main.py


from printer_proxy import PrinterProxy


def main():
    pp = PrinterProxy('Alice')
    print('The name is now' + pp.get_printer_name() + 'is.')
    pp.set_printer_name('Bob')
    print('The name is now' + pp.get_printer_name() + 'is.')
    pp.my_print('Hello, world.')

if __name__ == '__main__':
    main()

Execution result

The name is now Alice.
The name is now Bob.
Printer instance(Bob)Is being generated....Done.
=== Bob ===
Hello, world.

Summary

In the Proxy pattern, the Proxy role acts as an agent and takes over the processing as much as possible. In the sample program, by using the Proxy role, heavy processing (instantiation) could be delayed until the actual my_print.

If there are many functions that take a long time to initialize in the actual usage scene, I think that they will be initialized only when it is time to actually use those functions. I think it is one of the most commonly used design patterns.

reference

Recommended Posts

Design Pattern #Proxy
Design Pattern #Adapter
Design Pattern #Decorator
Design Pattern #Observer
Design Pattern #Facade
Design Pattern #Strategy
Design Pattern #Singleton
Learn the design pattern "Proxy" in Python
[Gang of Four] Design pattern learning --Proxy
Design Pattern #Factory Method
Design Pattern #Template Method
Proxy pattern in Java
Ore Ore Design Pattern: Glocal Variable
Python Design Pattern --Template method
[Gang of Four] Design pattern learning
GoF java design pattern rough summary
Learn the design pattern "Prototype" in Python
[Gang of Four] Design pattern learning --Singleton
[Gang of Four] Design Pattern Learning --Decorator
[Gang of Four] Design pattern learning --Visitor
[Gang of Four] Design pattern learning --Mediator
Learn the design pattern "Flyweight" in Python
Learn the design pattern "Memento" in Python
Learn the design pattern "Command" in Python
[Gang of Four] Design pattern learning --Iterator
Learn the design pattern "Visitor" in Python
Learn the design pattern "Mediator" in Python
Learn the design pattern "Decorator" in Python
Design pattern-Iterator
[Gang of Four] Design pattern learning --Facade
[Gang of Four] Design pattern learning --Composite
[Gang of Four] Design pattern learning --Prototype
GoF design pattern from the problem 1. Generation
Learn the design pattern "Iterator" in Python
I studied about design patterns (personal memo) Part 8 (Proxy pattern, Command pattern, Interpreter pattern)
[Gang of Four] Design pattern learning --Memento
[Gang of Four] Design pattern learning --State
[Gang of Four] Design pattern learning --Interpreter
[Gang of Four] Design pattern learning --Builder
Learn the design pattern "Strategy" in Python
[Gang of Four] Design pattern learning --Bridge
Learn the design pattern "Singleton" with Python
Learn the design pattern "State" in Python
Learn the design pattern "Adapter" in Python
[Gang of Four] Design pattern learning --Strategy
[Gang of Four] Design pattern learning --Adapter
Learn the design pattern "Facade" with Python
[Gang of Four] Design pattern learning --Observer
[Gang of Four] Design pattern learning --Command
GoF design pattern from the problem 3. Behavior
[Gang of Four] Design pattern learning --Fly Weight
[Gang of Four] Design pattern learning --Abstract Factory
Learn the design pattern "Abstract Factory" in Python
Learn the design pattern "Template Method" in Python
[Gang of Four] Design pattern learning --Factory Method
Learn the design pattern "Factory Method" in Python
[Gang of Four] Design pattern learning --Chain of Responsibility
[Gang of Four] Design pattern learning --Template Method