[PYTHON] I studied about design patterns (personal memo) Part 3 (Prototype pattern, Builder pattern)

Introduction

This article is a personal study memo. I am writing an article driven by the obsession that what I input must be output. I am writing this article on Qiita with the hope that someone who is familiar with it will be able to point out mistakes and give advice.

I live a working life as an engineer, but I haven't learned about design patterns properly, so I studied.

What is described here https://github.com/ck-fm0211/notes_desigh_pattern I'm uploading to.

Past log

I studied about design patterns (personal memo) Part 1 I studied about design patterns (personal memo) Part 2

Prototype pattern

--Pattern for creating an instance from the "prototype" prepared in advance --Example: --Consider a shape editor that only has the function of "drawing a straight line". ――When you want to draw a star shape with this figure editor, you can create a star shape by combining straight lines. ――If you want many stars, you need to repeat the process of drawing a star by combining straight lines. --In such a case, if you can create a star shape by registering the first created star shape (a collection of straight lines) as a "prototype" and copying it, the work can be simplified.

Actually use

Subject

--I want to copy the entire contents of the instance

# -*- coding:utf-8 -*-
import copy


def main():
    report1 = Report("title1", "content")
    report2 = copy.deepcopy(report1)

    print("title:", report1.title, report2.title)
    print("content:", report1.content, report2.content)


class Report:
    def __init__(self, title, content):
        self.title = title
        self.content = content


if __name__ == "__main__":
    main()
title: title1 title1
content: content content

--In the case of python, you can copy the entire contents of the instance by using copy.deepcopy. ――Let's extend it further and write a program that encloses a character string

# -*- coding:utf-8 -*-

import copy


class Product(object):
    def use(self, s):
        pass

    def createClone(self):
        pass


class Manager(object):
    __showcase = dict()

    def register(self, name, proto):
        self.__showcase[name] = proto

    def create(self, protoname):
        p = self.__showcase.get(protoname)
        return p.createClone()


class MessageBox(Product):
    def __init__(self, decochar):
        self.decochar = decochar

    def use(self, s):
        length = len(s)
        deco = self.decochar * (length + 4)
        print(deco)
        print(self.decochar, s, self.decochar)
        print(deco)

    def createClone(self):
        p = copy.deepcopy(self)
        return p


class Underline(Product):
    def __init__(self, ulchar):
        self.ulchar = ulchar

    def use(self, s):
        length = len(s)
        print('"%s"' % s)
        print(" %s " % (self.ulchar * length))

    def createClone(self):
        p = copy.deepcopy(self)
        return p


if __name__ == "__main__":
    manager = Manager()
    uline = Underline(".")
    mbox = MessageBox("*")
    sbox = MessageBox("/")
    pbox = MessageBox("+")
    uline2 = Underline("=")
    manager.register("strong message", uline)
    manager.register("star box", mbox)
    manager.register("slash box", sbox)
    manager.register("plus box", pbox)
    manager.register("under line", uline2)

    p1 = manager.create("strong message")
    p1.use("Hello, world.")
    p2 = manager.create("star box")
    p2.use("Hello, world.")
    p3 = manager.create("slash box")
    p3.use("Hello, world.")
    p4 = manager.create("plus box")
    p4.use("Hello, world.")
    p5 = manager.create("under line")
    p5.use("Hello, world.")

--Result

"Hello, world."
 .............
*****************
* Hello, world. *
*****************
/////////////////
/ Hello, world. /
/////////////////
+++++++++++++++++
+ Hello, world. +
+++++++++++++++++
"Hello, world."
 =============

Summary of Prototype patterns

class_image

Builder pattern

--Patterns for obtaining results in different expressions in the same creation process --Example: --Think about building a house ――To build a house, you need "what to use (= material)" and "how to build (= process)" --There are various materials such as wood, concrete, roof tiles, etc. ――There are various processes such as one-story, two-story, unusual house, etc. ――By preparing these patterns in advance, you can flexibly respond to the request "Please build a house with iron pillars and concrete walls and roofs in the process of building a slightly unusual one-story building". --The Builder pattern makes the creation of an object more flexible by combining what is called the Director that determines the "creation process" and what is called the Builder that determines the "expression form", and makes the object "". Pattern to be able to control the "creation process"

Actually use

Subject

--Consider making salt water and sugar water in a science experiment --The class that represents saline solution shall be given in the following source code (the same applies to the class that represents sugar water).

# -*- coding:utf-8 -*-


class SaltWater:

    salt = None
    water = None

    @staticmethod
    def salt_water(water, salt):
        SaltWater.salt = salt
        SaltWater.water = water

――Various requirements can be considered, but by using the Builder pattern, it will be possible to meet the following requirements. ――I want to use the solution obtained in the same process many times. ――I want to make sugar water in the same way. --In order to meet such demands, the Builder pattern creates classes that are Director and Builder. --The role of Director is to determine the "creation process", and the role of Builder is to determine the "expression form". --In the sample case, the role of the Director is to determine that "dissolve 40 g of solute in 100 g of solvent, discard 70 g of it, add 100 g of solvent, and finally add 15 g of solute." ――The role of the builder is to decide to use "water as the solvent and salt as the solute".

--The Builder interface looks like this:

from abc import ABCMeta, abstractmethod


class Builder(metaclass=ABCMeta):

    @abstractmethod
    def add_solute(self):
        pass

    @abstractmethod
    def add_solvent(self):
        pass

    @abstractmethod
    def avandon_solution(self):
        pass

    @abstractmethod
    def get_result(self):
        pass

--The Builder interface defines an addSolute method for adding solutes, an addSolvent method for adding solvents, an abandonSolution method for discarding solutions, and a getResult method for obtaining products. --In the Director class, the Builder interface is used to assemble the instance according to the "creation process".

class Director:

    def __init__(self):

        self.builder = Builder()

    def constract(self):
        self.builder.add_solvent(100)
        self.builder.add_solute(40)
        self.builder.abandon_solution(70)
        self.builder.add_solvent(100)
        self.builder.add_solute(15)

--The Director class only knows that it is given something that implements the Builder interface, it doesn't really need to know which Builder implementation class is being passed. This makes it easy to replace the Builder. --The SaltWaterBuilder class, which is a Builder implementation class, is as follows.

class SaltWaterBuilder(Builder):

    def __init__(self):
        self._salt_water = SaltWater(0,0)

    def add_solute(self, salt_amount):
        self._salt_water.salt += salt_amount

    def add_solvent(self, water_amount):
        self._salt_water.water += water_amount

    def abandon_solution(self, salt_water_amount):
        salt_delta = salt_water_amount * (self._salt_water.salt / (self._salt_water.salt + self._salt_water.water))
        water_delta = salt_water_amount * (self._salt_water.water / (self._salt_water.salt + self._salt_water.water))
        self._salt_water.salt -= salt_delta
        self._salt_water.water -= water_delta

    def get_result(self):
        return self._salt_water

――By designing like this, you can freely combine Director and Builder and create instances more flexibly.

--For example, by preparing a Director who knows the procedure for creating a document, HTMLBuilder to output for HTML, PlainTextBuilder to output plain text, etc., the same document can be output in different expression formats according to the request. become able to. class_image1

Summary of Builder patterns

class_image2

Recommended Posts

I studied about design patterns (personal memo) Part 3 (Prototype pattern, Builder pattern)
I studied about design patterns (personal memo) Part 5 (Composite pattern, Decorator pattern, Visitor pattern)
I studied about design patterns (personal memo) Part 4 (AbstractFactory pattern, Bridge pattern, Strategy pattern)
I studied about design patterns (personal memo) Part 8 (Proxy pattern, Command pattern, Interpreter pattern)
I studied about design patterns (personal memo) Part 7 (Observer pattern, Memento pattern, State pattern, Flyweight pattern)
I studied about design patterns (personal memo) Part 6 (Chain of Responsibility pattern, Facade pattern, Mediator pattern)
Design Pattern #Builder
I wrote a design pattern in kotlin Prototype
I studied about Systemd properly