2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Pythonで実装するCompositeパターン:ツリー構造を統一インターフェースで扱う

Posted at

概要

Composite(コンポジット)パターンは、
個々のオブジェクト(葉)と複合オブジェクト(枝)を同一のインターフェースで扱えるように構造化する設計パターンである。

ディレクトリ構造やUIツリー、組織階層などのツリー状データを、統一的・再帰的に操作するための強力なアプローチを提供する。


1. なぜCompositeが必要か?

❌ ツリー構造を持つデータに対し、個別にif分岐して処理すると保守性が低下

if isinstance(node, Folder):
    for child in node.children:
        ...
elif isinstance(node, File):
    ...

個々の型に応じて処理を分ける必要があり、拡張が困難


✅ File も Folder も同じ Component インターフェースで扱えるようにする

for component in root.get_children():
    component.show()

構造を問わず、共通インターフェースでツリー全体を統一的に処理可能


2. 基本構造

✅ Component(共通インターフェース)

class FileSystemComponent:
    def show(self, indent=0):
        raise NotImplementedError

✅ Leaf(葉ノード:ファイル)

class File(FileSystemComponent):
    def __init__(self, name):
        self.name = name

    def show(self, indent=0):
        print("  " * indent + f"File: {self.name}")

✅ Composite(複合ノード:フォルダ)

class Folder(FileSystemComponent):
    def __init__(self, name):
        self.name = name
        self.children = []

    def add(self, component: FileSystemComponent):
        self.children.append(component)

    def show(self, indent=0):
        print("  " * indent + f"Folder: {self.name}")
        for child in self.children:
            child.show(indent + 1)

✅ 使用例

root = Folder("root")
docs = Folder("docs")
images = Folder("images")

root.add(docs)
root.add(images)

docs.add(File("README.md"))
docs.add(File("CONTRIBUTE.md"))
images.add(File("logo.png"))

root.show()

出力:

Folder: root  
  Folder: docs  
    File: README.md  
    File: CONTRIBUTE.md  
  Folder: images  
    File: logo.png

3. Python的応用:辞書・JSON構造もComposite的に処理可能

def show_dict(obj, indent=0):
    if isinstance(obj, dict):
        for k, v in obj.items():
            print("  " * indent + str(k))
            show_dict(v, indent + 1)
    elif isinstance(obj, list):
        for item in obj:
            show_dict(item, indent + 1)
    else:
        print("  " * indent + str(obj))

辞書・リスト・プリミティブの階層構造もCompositeで一元処理できる


4. 実務ユースケース

✅ ファイルシステムや構成ツリーの表示・操作

→ 階層的構造を持つデータの一括表示・探索処理


✅ GUIのレイアウトツリー(ウィジェット・コンテナ)

→ 親コンポーネントも子と同じように描画・処理できる


✅ 組織図、マネージャ・従業員の階層構造

上司も部下も「人間」として同じインターフェースで扱う


✅ ドキュメント構造(セクション・見出し・段落)

→ 構造文書の整形・レンダリングに再帰的構造が有効


5. よくある誤用と対策

❌ Composite側が巨大化してすべての操作を抱えてしまう

→ ✅ LeafとCompositeに明確な責務分離を設ける


❌ 子の管理(add/remove)がLeaf側にも必要だと勘違いする

→ ✅ add()remove()はComposite専用メソッドとして設計


❌ 構造が深くなりすぎてパフォーマンスが低下

→ ✅ キャッシュや幅優先処理を活用して再帰の負荷を軽減


結語

Compositeパターンとは、“ひとつのモノと多くのモノを同一の方法で扱うための階層的知性”である。

  • 単体と複合体を統一的に操作でき、ツリー構造に対する処理がシンプルかつ拡張可能に
  • 再帰的構造の表現を簡潔にし、責任の階層を視覚化できる設計
  • Pythonではクラスや再帰構造により、柔らかく強い構造を実現可能

Pythonicとは、“構造を持つものは、構造をそのまま操作できること”。
Compositeパターンはその再帰の知性を、あらゆる階層構造の操作性へと昇華する技法である。

2
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?