2
3

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 isinstance(node, Leaf):
    node.draw()
else:
    for child in node.children:
        child.draw()

条件分岐による処理の分散・冗長化


✅ 全てを draw() に統一して再帰的に呼び出す構造へ

root.draw()

クライアントコードが構造を意識せず操作可能


2. 基本構造

✅ Componentインターフェース

class Graphic:
    def draw(self):
        raise NotImplementedError

✅ Leaf(葉ノード)

class Circle(Graphic):
    def draw(self):
        print("● Circle")

✅ Composite(枝ノード)

class GraphicGroup(Graphic):
    def __init__(self):
        self.children = []

    def add(self, graphic: Graphic):
        self.children.append(graphic)

    def draw(self):
        print("[Group] Start")
        for child in self.children:
            child.draw()
        print("[Group] End")

✅ 使用例

root = GraphicGroup()
circle1 = Circle()
circle2 = Circle()

subgroup = GraphicGroup()
subgroup.add(circle2)

root.add(circle1)
root.add(subgroup)

root.draw()

出力:

[Group] Start  
● Circle  
[Group] Start  
● Circle  
[Group] End  
[Group] End

3. Python的応用:ファイルツリー風Composite構造

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

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

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

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

    def add(self, node: FileSystemNode):
        self.children.append(node)

    def show(self, indent=0):
        print("  " * indent + f"[{self.name}]")
        for child in self.children:
            child.show(indent + 1)
root = Folder("project")
root.add(File("README.md"))
src = Folder("src")
src.add(File("main.py"))
root.add(src)

root.show()

出力:

[project]  
  - README.md  
  [src]  
    - main.py

4. 実務ユースケース

✅ UI構築(ページ内コンポーネントの入れ子構造)

Panel, Button, TextBox などを一貫した操作で管理可能


✅ ファイルシステム・階層型メニューの表現

ルートから末端まで統一操作


✅ DOM操作・シーングラフ・パーティクル構造

構造と描画の分離を再帰で美しく表現


✅ ワークフローや処理フローの構造設計

タスクサブタスク集合 を同一視できる構成


5. よくある誤用と対策

❌ CompositeにLeafの操作を持たせてしまう

→ ✅ 共通インターフェースは最小限にし、不要な操作を排除


❌ 子ノードの操作を外から乱用する(カプセル化の破壊)

→ ✅ add()/remove()はCompositeの責務、Leafでは持たせない


❌ 構造の再帰処理が深くなりすぎてパフォーマンス劣化

→ ✅ 最大深度・遅延描画・メモ化等の最適化を検討


結語

Compositeパターンとは、“構造の深さを抽象の一貫性で隠し、操作を平坦にする設計”である。

  • 個と集合を同じように扱うことで、再帰構造の一貫性と汎用性を獲得
  • 入れ子構造やツリー構造の操作を、再帰と抽象で美しく設計
  • Pythonでは柔軟なインターフェース設計と再帰構文で、極めて直感的に実装可能

Pythonicとは、“階層に意味を持たせながら、それを意識させないように操作すること”。
Compositeパターンはその均質性と抽象力を、再帰の奥に潜ませる技法である。

2
3
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
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?