Pythonでデザインパターン 拾壱ノ型「Composite」
今回はPythonの勉強しながらデザインパターンのCompositeをやってみました。
他のパターンにつきましては、以下の目次記事をご参照ください。
Compositeパターンとは
直訳すると「複合物」や「混合物」みたいな意味でしょうか。
wikiには「ディレクトリとファイルなどのような、木構造を伴う再帰的なデータ構造を表すことができる」とあります。
このパターンはwikiにもあるとおりオブジェクトで木構造を表現するためのものです!
Compositeパターンについて考えてみる
木構造というとファイル構造が一番イメージしやすいですかね?
今回はCompositeパターンを使ってディレクトリツリーを作ってみたいと思います(・`ω´・)b
まずファイルやディレクトリのベースとなる抽象クラスEntryを用意します。
from abc import ABCMeta, abstractmethod class Entry(metaclass=ABCMeta) : @abstractmethod def getName(self) : pass @abstractmethod def printList(self, prefix) : pass
Entryを継承してファイルを示すクラスFileを用意します。
class File(Entry): def __init__(self, name) -> None: self.__name = name def getName(self) -> str: return self.__name def printList(self, prefix: str) -> None: uri = prefix + "/" + self.__name print(uri)
Entryを継承してディレクトリを示すクラスDirectoryを用意します。
Directoryクラスには新しいEntryを追加するaddEntryメソッドを備えます。
FileクラスにはaddEntryメソッドがないので新しいEntryを追加できません。
似たようなコードが世の中にはいっぱいあるのでこのあたりの説明は不要ですかね(;^ω^)
class Directory(Entry): def __init__(self, name) -> None: self.__name = name self.__directory = [Entry] def getName(self) -> str: return self.__name def addEntry(self, entry: Entry) -> [Entry]: self.__directory.append(entry) return self.__directory def printList(self, prefix: str) -> None: uri = prefix + "/" + self.__name print(uri) entryNum = len(self.__directory) for i in range(entryNum): self.__directory[i].printList(uri)
あとはDirectoryクラスを作成してその中にDirectoryクラスやFileクラスを追加していきます。
# ディレクトリを作成 dir = Directory("ディレクトリ名") # ファイルを追加 dir.addEntry(File("ファイル名")) # ディレクトリを追加 dir.addEntry(Directory("ディレクトリ名")) # 再帰的にディレクトリとファイルを追加 dir.addEntry(Directory("ディレクトリ名").addEntry(File("ファイル名")))
サンプルコード
これまでのコードの全体像です。
from abc import ABCMeta, abstractmethod class Entry(metaclass=ABCMeta): @abstractmethod def getName(self) -> str: pass @abstractmethod def printList(self, prefix: str) -> None: pass def printList(self): pass class File(Entry): def __init__(self, name) -> None: self.__name = name def getName(self) -> str: return self.__name def printList(self, prefix: str) -> None: uri = prefix + "/" + self.__name print(uri) class Directory(Entry): def __init__(self, name) -> None: self.__name = name self.__directory = [Entry] def getName(self) -> str: return self.__name def addEntry(self, entry: Entry) -> [Entry]: self.__directory.append(entry) return self.__directory def printList(self, prefix: str) -> None: uri = prefix + "/" + self.__name print(uri) entryNum = len(self.__directory) for i in range(entryNum): self.__directory[i].printList(uri) if __name__ == "__main__" : # rootディレクトリを作成 rootDir = Directory("root") # サブフォルダを作成 folder1 = Directory("Folder1") folder2 = Directory("Folder2") folder3 = Directory("Folder3") folder4 = Directory("Folder4") # フォルダを追加 rootDir.addEntry(folder1) folder1.addEntry(folder2) rootDir.addEntry(folder3) folder3.addEntry(folder4) # ファイルを作成 file1 = File("file1") file2 = File("file2") file3 = File("file3") file4 = File("file4") file5 = File("file5") file6 = File("file6") # ファイルを追加 rootDir.addEntry(file1) folder1.addEntry(file2) folder2.addEntry(file3) folder3.addEntry(file4) folder4.addEntry(file5) folder4.addEntry(file6) # ディレクトリツリーを表示 rootDir.printList(".")
実行結果はこんな感じです!
$ python Composite.py ./root ./root/Folder1 ./root/Folder1/Folder2 ./root/Folder1/Folder2/file3 ./root/Folder1/file2 ./root/Folder3 ./root/Folder3/Folder4 ./root/Folder3/Folder4/file5 ./root/Folder3/Folder4/file6 ./root/Folder3/file4 ./root/file1