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.
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 UML class diagram (The above is quoted from Wikipedia)
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
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
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
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))
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)
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())
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()
Add an exception class
entry.py
class FileTreatmentException(Exception):
def __init__(self,*args,**kwargs):
self.message = "FileTreatmentException"
-[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