Python基礎 オブジェクト指向13(Composite) 構造に関するデザインパターン
| 登録日 | :2025/10/10 06:19 |
|---|---|
| カテゴリ | :Python基礎 |
Composite
ツリー構造を持つデータに再起的な処理を行えるようにするパターン
- ツリー構造:一つの要素に複数の子要素を持ち、枝分かれしていく構造
- 任意の枝や末端の葉に対して、共通の手順でアクセスするためのAPIを提供する
構成要素
Component
- 抽象クラスもしくはインターフェース
- クライアントからアクセスさせるためのAPIを定義
Leaf
- Componentを継承(実装)する子クラス
- ツリー構造の末端である葉に相当するクラス
- 子に相当するオブジェクトは持たない
Composite
- Componentを継承(実装)する子クラス
- ツリー構造の中で任意の枝に相当するクラス
- 属性に子に相当するオブジェクトを保持
- Componentクラスのメソッド実装に加えて、子要素を追加・削除するためのメソッドも定義する
オブジェクト指向的要素
「ポリモーフィズム」を利用したパターン
- Componentでクライアントに対してアクセスさせるための共通APIを定義
- クライアントは共通APIのみを使用することで、CompositeクラスやLeafクラスを意識する必要がなく同一のものとして扱える
- Compositeクラスは子クラスに相当するComponent型のオブジェクトを保持している
- Compositeクラスは子クラスの共通APIのみを使用することで、子クラスが枝なのか葉なのかを意識する必要がなくなる
メリット・デメリット
メリット
-
複雑なツリー構造を簡単に扱うことができる
(if elseなどによる分岐を減らすことができる) -
新しい枝葉を簡単に追加できる
デメリット
- 枝と葉の機能が大きく異なる場合は、共通のAPIを作ることが困難
使い所
再起的なツリー構造を実装する場合
- ディレクトリツリー、組織階層、DOMツリーなど
サンプルコード
例)ディレクトリツリー
from abc import ABCMeta, abstractmethod
from typing import List
class Entry(metaclass=ABCMeta):
def __init__(self, _name: str):
self.__name = _name
@property
def name(self) -> str:
return self.__name
@abstractmethod
def get_size(self) -> int:
pass
@abstractmethod
def remove(self):
pass
class File(Entry):
""" Leaf class"""
def __init__(self, _name: str, _size: int):
super().__init__(_name)
self.__size = _size
def get_size(self) -> int:
return self.__size
def remove(self):
print(f'Remove:{self.name}')
class Directory(Entry):
def __init__(self, _name: str):
super().__init__(_name)
self.__children: List[Entry] = []
def get_size(self) -> int:
size = 0
for child in self.__children:
size += child.get_size()
return size
def remove(self):
for child in self.__children:
child.remove()
print(f'Remove : {self.name}')
def add(self, _child: Entry):
self.__children.append(_child)
def client(_entry: Entry):
print(_entry.name)
print(_entry.get_size())
_entry.remove()
if __name__ == '__main__':
dir1 = Directory('design_pattern1')
dir2 = Directory('Composite')
file1 = File('composite.py', 100)
file2 = File('practice.png', 200)
dir2.add(file1)
dir2.add(file2)
dir1.add(dir2)
client(dir1)