nono blog
楽しい人生を送りたい!
ITスキル

pythonプログラム デザインパターン(Composite)

構造パターンの一つであるCompositeパターン

Compositeパターンとは

ツリー構造(階層構造)となるようにプログラミングするパターン。
どの節にどの葉を要素として追加していくのかを把握することが難しい場合、Compositパターンを用いてツリー構造を表現する。

(目的)
ツリー構造階層をわかりやすく表現する。

(仕組み)
葉(Reaf)と節(Composit)の共通機能を定義したComponetを作成する。
Componetを継承した、CompositとReafを作成する。
Compositをインスタンス化してそのCompositeの子要素とする。
Composit, Reafを追加していく。

(構成要素)
Component: CompositeとReafの共通機能を持った抽象クラス
Composite: 容器を表す役を持ったクラス。この中に、Composite,Reafを入れていき、
       階層構造を作成する
Reaf: 中身を表す役のクラス。この中には要素を入れることができない。

サンプルプログラム

pythonによるCompositeパターンのサンプルプログラム。

ディレクトリの階層を表示する。

# composite.py
from abc import ABC, abstractmethod, abstractproperty

"""ディレクトリとファイルの構造を表現してみる"""
class Componet(ABC):

    @abstractproperty
    def name(self):
        pass

    @abstractproperty
    def size(self):
        pass

    @property
    def parent(self):
        return self._parent

    @parent.setter
    def parent(self, parent):
        self._parent = parent

    @abstractmethod
    def print_list(self, path):
        pass

    def __str__(self):
        return f"{self.name} ({self.size})"


class File(Componet):

    def __init__(self, name, size):
        self.__name = name
        self.__size = size
        self._parent = None

    @property
    def name(self):
        return self.__name

    @property
    def size(self):
        return self.__size

    def print_list(self, path=''):
        """ retrun path and file name."""
        print(path + '/' + str(self))


class Directory(Componet):

    def __init__(self, name):
        self.__name = name
        self.__children = {} # ファイルやディレクトリを入れていく
        self._parent = None

    @property
    def name(self):
        return self.__name

    @property
    def size(self):
        file_size = 0
        for child in self.__children:
            file_size += self.__children[child].size
        return file_size

    def add_child(self, child):
        self.__children[child.name] = child
        child.parent = self

    def remove_child(self, child):
        if child.name in self.__children:
            del self.__children[child.name]
            child.parent = None

    def print_list(self, path=''):
        print(path + '/' + str(self))
        for child in self.__children:
            self.__children[child].print_list(
                path + '/' + self.name
            )


if __name__ == '__main__':
    file1 = File('temp1.txt', 1000)
    file2 = File('temp2.txt', 2000)
    file3 = File('temp3.txt', 3000)
    file4 = File('temp4.txt', 4000)

    root_dir = Directory('root')
    home_dir = Directory('home')
    sys_dir = Directory('sys')
    taro_dir = Directory('taro')

    root_dir.add_child(home_dir)
    root_dir.add_child(sys_dir)
    root_dir.print_list()

    print('-'*50)
    home_dir.add_child(taro_dir)
    taro_dir.add_child(file1)
    taro_dir.add_child(file2)

    home_dir.add_child(file3)
    sys_dir.add_child(file4)

    root_dir.print_list()

    print('-'*50)
    sys_dir.remove_child(file4)
    root_dir.print_list()