🗂

# デザインパターンを学ぶ #9 コンポジット(Composite)

に公開

1. はじめに

デザインパターン学習シリーズの第8回。今回は Composite(コンポジット)パターンを取り上げます。
目的は 部分(Leaf)と全体(Composite)を同一視して扱えるようにする 方法を理解することです。

2. Compositeとは

Compositeパターンは、個と集合を同じインターフェースで扱う設計です。
ツリー構造(階層構造)を意識せずに操作できるため、フォルダとファイル、カテゴリと商品などをまとめて扱いたい場面で有効です。

3. 構成要素

  • Component:共通インターフェース
  • Leaf:子を持たない末端要素
  • Composite:複数の子(Component)を保持し、操作を子に再帰的に委譲する

4. 実装例(PHP)

<?php

interface Item {
    public function getPrice(): int;
    public function getName(): string;
}

final class Product implements Item {
    public function __construct(
        private string $name,
        private int $price
    ) {}

    public function getPrice(): int { return $this->price; }
    public function getName(): string { return $this->name; }
}

final class ProductGroup implements Item {
    /** @var Item[] */
    private array $children = [];

    public function __construct(private string $name) {}

    public function add(Item $item): void {
        $this->children[] = $item;
    }

    public function getPrice(): int {
        return array_sum(array_map(fn($c) => $c->getPrice(), $this->children));
    }

    public function getName(): string { return $this->name; }
}

// 利用例
$ramen = new Product('ラーメン', 800);
$gyoza = new Product('餃子', 300);

$set = new ProductGroup('セットA');
$set->add($ramen);
$set->add($gyoza);

echo $set->getName() . ' 合計: ' . $set->getPrice() . "円\n";
// 出力: セットA 合計: 1100円

5. 使いどころ

  • 商品カテゴリ・フォルダ・組織図などのツリー構造
  • 店舗グループやチーム階層など、部分集合の値を親で集計したい場面

6. メリット

  • 個と集合を同じように扱える
  • クライアント側の if 分岐をなくせる
  • 再帰処理でツリー構造を自然に表現できる

7. 注意点

  • ツリー構造でないものに無理に適用すると過剰設計になりやすい
  • 深い階層での再帰集計はパフォーマンス問題になりやすい(キャッシュや差分更新を検討する)

8. まとめ

Compositeは「部分と全体を同一視して扱う」構造パターンです。
次回は関連する構造パターンのProxy に進むと理解がつながりやすいです。

Discussion