[GO] Learn the design pattern "Composite" in Python

As a material for learning GoF design patterns, the book "Introduction to Design Patterns Learned in the Augmented and Revised Java Language" seems to be helpful. However, since the examples taken up are based on JAVA, I tried the same practice in Python to deepen my understanding.

■ Composite (composite pattern)

The Composite pattern is one of the design patterns defined by GoF (Gang of Four; 4 gangs). It belongs to "Structural pattern". The Composite pattern can be used to represent recursive data structures with tree structures, such as directories and files. The objects that appear in the Composite pattern are "branches" and "leaves", which implement a common interface. Therefore, there is an advantage that branches and leaves can be treated in the same way.

UML class and object diagram W3sDesign_Composite_Design_Pattern_UML.jpg UML class diagram composite.png (The above is quoted from Wikipedia)

□ Memorandum

I'm hungry for a quote from the book "Introduction to Design Patterns Learned in the Java Language".

Some directories contain files or other directories (subdirectories). And again, that subdirectory may contain other files and subdirectories. Directories create such a "nested" structure, a recursive structure. ... (snip) The Composite pattern is for creating such a structure, ** equating the container with the contents and creating a recursive structure ** design pattern

■ "Composite" sample program

Actually, I would like to run a sample program that utilizes the Composite pattern and check the following behavior.

--Try adding subdirectories and files to the directory of the root entry --Try adding the directory of the user entry to the directory of the root entry, and then the subdirectories and files. --Dare to add a directory to the file and make sure it fails

$ python Main.py 
Making root entries...
/root (30000)
/root/bin (30000)
/root/bin/vi (10000)
/root/bin/latex (20000)
/root/tmp (0)
/root/usr (0)

Making user entries...
/root (31500)
/root/bin (30000)
/root/bin/vi (10000)
/root/bin/latex (20000)
/root/tmp (0)
/root/usr (1500)
/root/usr/yuki (300)
/root/usr/yuki/diary.html (100)
/root/usr/yuki/Composite.java (200)
/root/usr/hanako (300)
/root/usr/hanako/memo.tex (300)
/root/usr/tomura (900)
/root/usr/tomura/game.doc (400)
/root/usr/tomura/junk.mail (500)

Occurring Exception...
FileTreatmentException

■ Details of sample program

Similar code has been uploaded to the Git repository. https://github.com/ttsubo/study_of_design_pattern/tree/master/Composite

--Directory structure

.
├── Main.py
└── entry.py

(1) The role of Leaf

It is a role that represents the "contents". Nothing else can be in this role. In the sample program, the File class serves this role.

entry.py


class File(Entry):
    def __init__(self, name, size):
        self.name = name
        self.size = size

    def getName(self):
        return self.name

    def getSize(self):
        return self.size

    def _printList(self, prefix=''):
        print("{0}/{1}".format(prefix, self))

(2) The role of Composite

It is a role that represents a "container". You can enter the role of Leaf or the role of Composite. In the sample program, the Directory class serves this role.

entry.py


class Directory(Entry):
    def __init__(self, name):
        self.name = name
        self.directory = []

    def getName(self):
        return self.name

    def getSize(self):
        size = 0
        for d in self.directory:
            size += d.getSize()
        return size

    def add(self, entry):
        entry.path = self.name
        self.directory.append(entry)

    def _printList(self, prefix=''):
        print(prefix + "/" + str(self))
        for e in self.directory:
            e._printList(prefix + '/' + self.name)

(3) Role of Component

This is a role to equate the Leaf role with the Composite role. The Component role is realized as a superclass common to the Leaf role and the Composite role. In the sample program, the ʻEntry` class serves this role.

entry.py


from abc import ABCMeta, abstractmethod

... (snip)

class Entry(metaclass=ABCMeta):
    @abstractmethod
    def getName(self):
        pass

    @abstractmethod
    def getSize(self):
        pass

    def add(self, entry):
        raise FileTreatmentException

    def printList(self):
        self._printList()

    @abstractmethod
    def _printList(self, prefix=''):
        pass

    def __str__(self):
        return "{0} ({1})".format(self.getName(), self.getSize())

(4) The role of Client

In the sample program, the startMain method serves this role.

Main.py


from abc import ABCMeta, abstractmethod
from entry import Directory, File, FileTreatmentException


def startMain():
    try:
        print("Making root entries...")
        rootdir = Directory("root")
        bindir = Directory("bin")
        tmpdir = Directory("tmp")
        usrdir = Directory("usr")

        rootdir.add(bindir)
        rootdir.add(tmpdir)
        rootdir.add(usrdir)

        bindir.add(File("vi", 10000))
        bindir.add(File("latex", 20000))
        rootdir.printList()

        print("")
        print("Making user entries...")
        yuki = Directory("yuki")
        hanako = Directory("hanako")
        tomura = Directory("tomura")

        usrdir.add(yuki)
        usrdir.add(hanako)
        usrdir.add(tomura)

        yuki.add(File("diary.html", 100))
        yuki.add(File("Composite.java", 200))
        hanako.add(File("memo.tex", 300))
        tomura.add(File("game.doc", 400))
        tomura.add(File("junk.mail", 500))
        rootdir.printList()

        print("")
        print("Occurring Exception...")
        tmpfile = File("tmp.txt", 100)
        bindir = Directory("bin")
        tmpfile.add(bindir)
    except FileTreatmentException as ex:
        print(ex.message)

if __name__ == '__main__':
    startMain()

(5) Other

Add an exception class

entry.py


class FileTreatmentException(Exception):
    def __init__(self,*args,**kwargs):
        self.message = "FileTreatmentException"

■ Reference URL

-[Finishing "Introduction to Design Patterns Learned in Java Language" (Not)](https://medium.com/since-i-want-to-start-blog-that-looks-like-men-do/java Introduction to Design Patterns Learned in Language-Finishing-Not-2cc9b34a30b2)

Recommended Posts

Learn the design pattern "Composite" in Python
Learn the design pattern "Prototype" in Python
Learn the design pattern "Flyweight" in Python
Learn the design pattern "Memento" in Python
Learn the design pattern "Proxy" in Python
Learn the design pattern "Command" in Python
Learn the design pattern "Visitor" in Python
Learn the design pattern "Mediator" in Python
Learn the design pattern "Decorator" in Python
Learn the design pattern "Iterator" in Python
Learn the design pattern "Strategy" in Python
Learn the design pattern "State" in Python
Learn the design pattern "Adapter" in Python
Learn the design pattern "Abstract Factory" in Python
Learn the design pattern "Template Method" in Python
Learn the design pattern "Factory Method" in Python
Learn the design pattern "Chain of Responsibility" in Python
Learn the design pattern "Singleton" with Python
Learn the design pattern "Facade" with Python
Implement the Singleton pattern in Python
Singleton pattern in Python
Visitor pattern in Python
Download the file in Python
Find the difference in Python
Learn cumulative sum in Python
Design Patterns in Python: Introduction
Learn exploration in Python # 1 Full exploration
Python Design Pattern --Template method
Getting the arXiv API in Python
Python in the browser: Brython's recommendation
Hit the Sesami API in Python
Get the desktop path in Python
Get the script path in Python
In the python command python points to python3.8
Hit the web API in Python
I wrote the queue in Python
Calculate the previous month in Python
Examine the object's class in python
Get the desktop path in Python
Get the host name in Python
Access the Twitter API in Python
The first step in Python Matplotlib
I wrote the stack in Python
Master the weakref module in Python
Learn the basics of Python ① Beginners
Load the remote Python SDK in IntelliJ
Try using the Wunderlist API in Python
[Python Kivy] About changing the design theme
Try using the Kraken API in Python
Learn the basics while touching python Variables
Write the test in a python docstring
OR the List in Python (zip function)
Display Python 3 in the browser with MAMP
Tweet using the Twitter API in Python
Check if the URL exists in Python
Associate the table set in python models.py
Run the Python interpreter in a script
The result of installing python in Anaconda
[Gang of Four] Design pattern learning --Composite
What is "mahjong" in the Python library? ??
Read the file line by line in Python