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.
I studied about design patterns (personal memo) Part 1 I studied about design patterns (personal memo) Part 2
--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.
--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."
=============
--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"
--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".
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.
Recommended Posts