Python デザインパターン サンプルコード Template Method
結城 浩「Java言語で学ぶデザインパターン入門」をPython化
Python3(3.11)で動くソースコード(.pyファイル .ipynbファイル)あります
「anaconda3」on .py「PyCharm」.ipynb「Jupyter Notebook」
root = bin = vi(10000) = latex(20000) = tmp = usr = yuki = diary.html(100) = Composite.java(200) = hanako = memo.tex(300) = tomura = game.doc(400) = junk.mail(500)このような特徴のあるツリー構造を従来からあるグラフ理論のアルゴリズムではなくオブジェクト指向の考えで実装すると,GoF が言うようにフォルダ(ディレクトリ)とファイルを区別することなく扱うことができるようになる。結城氏はこのことを容器と中身の同一視と表現した。
(2023-11-18)Python3.11で動作確認済み
Entry (getName, getSize, printList) ↑ ↑ File Directory (getName, getSize, printList) (getName, getSize, printList, add)class Entry は,抽象メソッドでありテンプレートです。
usrdir = Directory("usr") # "usr"をインスタンス化してインスタンス「usrdir」を得る rootdir.add(usrdir) # 「usrdir」をインスタンス「rootdir」のリストに加える yuki = Directory("yuki") # "yuki"をインスタンス化してインスタンス「yuki」を得る usrdir.add(yuki) # 「yuki」をインスタンス「usrdir」のリストに加える yuki.add(File("diary.html", 100)) # "diary.html"をインスタンス化して # インスタンス「yuki」のリストに加えるこのようにしてすべてのノード(ファイルとフォルダ(ディレクトリ))はインスタンス化されます。そのうち各ディレクトリの各インスタンスはそれぞれリストを持っています。各ディレクトリの中身(子ノード)はそのリストに入ることになります。上の例はリストが3つあり最後のファイルも含めて4階層になっていることが判ると思います。
42 43 44 45 46 47
def getSize(self): self.size = 0 it = iter(self.directory) for entry in it: self.size += entry.getSize() return self.size
51 52 53 54 55
def printList(self, prefix): sys.stdout.write("{0}/{1}\n".format(prefix, self)) it = iter(self.directory) for entry in it: entry.printList("{0}/{1}".format(prefix, self.name))
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88
#!/usr/bin/env python3 # -*- coding: utf-8 -*- import sys from abc import ABCMeta, abstractmethod class Entry(metaclass = ABCMeta): @abstractmethod def getName(self): pass @abstractmethod def getSize(self): pass def add(self, entry): raise FileTreatmentException @abstractmethod def printList(self, prefix): pass def printListr(self): self.printList("") def __str__(self): return "{} ({})".format(self.getName(), self.getSize()) 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): sys.stdout.write("{}/{}\n".format(prefix, self)) class Directory(Entry): def __init__(self, name): self.name = name self.directory = [] def getName(self): return self.name def getSize(self): self.size = 0 it = iter(self.directory) for entry in it: self.size += entry.getSize() return self.size def add(self, entry): self.directory.append(entry) return self def printList(self, prefix): sys.stdout.write("{}/{}\n".format(prefix, self)) it = iter(self.directory) for entry in it: entry.printList("{}/{}".format(prefix, self.name)) class FileTreatmentException(Exception): pass def main(): sys.stdout.write("Making root entries...\n") 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.printListr() sys.stdout.write("Making root entries...\n") 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.printListr() if __name__ == '__main__': main() """標準出力 Making root entries... /root (30000) /root/bin (30000) /root/bin/vi (10000) /root/bin/latex (20000) /root/tmp (0) /root/usr (0) Making root 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) """