🧩 Composite パターン
✅ 設計意図
- オブジェクトを木構造(ツリー構造)で表現し、「個」と「集合」を同一視して扱えるようにする
- 大規模な
God Object
が、部分構造を持っている場合に有効
✅ 適用理由
God Object
の中で、UI 構成、ドキュメント構成、組織構成など再帰的な構造を持っている場合- 各構成要素を再利用しやすく、追加や削除もシンプルにできる
✅ 向いているシーン
- フォルダ構成、メニュー構造、GUI パーツなど階層的な構造を扱うクラス
- 子要素を再帰的に持つデータ構造の整理
✅ コード例
- TypeScript
- PHP
- Python
// Component(共通インターフェース)
interface OrganizationUnit {
getName(): string;
print(indent?: string): void;
}
// Leaf(個々の要素)
class Employee implements OrganizationUnit {
constructor(private name: string) {}
getName(): string {
return this.name;
}
print(indent: string = ""): void {
console.log(`${indent}- ${this.name}`);
}
}
// Composite(集合)
class Department implements OrganizationUnit {
private members: OrganizationUnit[] = [];
constructor(private name: string) {}
add(unit: OrganizationUnit) {
this.members.push(unit);
}
getName(): string {
return this.name;
}
print(indent: string = ""): void {
console.log(`${indent}+ ${this.name}`);
this.members.forEach((member) => member.print(indent + " "));
}
}
// 利用例
const devTeam = new Department("開発部");
devTeam.add(new Employee("Hiroshi"));
devTeam.add(new Employee("Satoshi"));
const qaTeam = new Department("QA部");
qaTeam.add(new Employee("Yuki"));
const company = new Department("MyCompany");
company.add(devTeam);
company.add(qaTeam);
company.print();
<?php
// Component インターフェース
interface OrganizationUnit {
public function getName(): string;
public function print(string $indent = ""): void;
}
// Leaf
class Employee implements OrganizationUnit {
private string $name;
public function __construct(string $name) {
$this->name = $name;
}
public function getName(): string {
return $this->name;
}
public function print(string $indent = ""): void {
echo "{$indent}- {$this->name}\\n";
}
}
// Composite
class Department implements OrganizationUnit {
private string $name;
private array $members = [];
public function __construct(string $name) {
$this->name = $name;
}
public function add(OrganizationUnit $unit): void {
$this->members[] = $unit;
}
public function getName(): string {
return $this->name;
}
public function print(string $indent = ""): void {
echo "{$indent}+ {$this->name}\\n";
foreach ($this->members as $member) {
$member->print($indent . " ");
}
}
}
// 利用例
$devTeam = new Department("開発部");
$devTeam->add(new Employee("Hiroshi"));
$devTeam->add(new Employee("Satoshi"));
$qaTeam = new Department("QA部");
$qaTeam->add(new Employee("Yuki"));
$company = new Department("MyCompany");
$company->add($devTeam);
$company->add($qaTeam);
$company->print();
from abc import ABC, abstractmethod
# Component
class OrganizationUnit(ABC):
@abstractmethod
def get_name(self) -> str:
pass
@abstractmethod
def print(self, indent: str = ""):
pass
# Leaf
class Employee(OrganizationUnit):
def __init__(self, name: str):
self.name = name
def get_name(self) -> str:
return self.name
def print(self, indent: str = ""):
print(f"{indent}- {self.name}")
# Composite
class Department(OrganizationUnit):
def __init__(self, name: str):
self.name = name
self.members: list[OrganizationUnit] = []
def add(self, unit: OrganizationUnit):
self.members.append(unit)
def get_name(self) -> str:
return self.name
def print(self, indent: str = ""):
print(f"{indent}+ {self.name}")
for member in self.members:
member.print(indent + " ")
# 利用例
dev_team = Department("開発部")
dev_team.add(Employee("Hiroshi"))
dev_team.add(Employee("Satoshi"))
qa_team = Department("QA部")
qa_team.add(Employee("Yuki"))
company = Department("MyCompany")
company.add(dev_team)
company.add(qa_team)
company.print()
✅ 解説
このコードは Composite
パターン を使用して、組織構造のような階層的なデータを統一的に扱う設計を実現している。Composite
パターンは、「個」と「集合」を同一視して操作できるようにするデザインパターンであり、ツリー構造を扱う際に非常に有効。
Composite
パターンの概要- Component: 共通インターフェースを定義し、「個」と「集合」を同一視して扱うための基盤を提供する
- このコードでは
OrganizationUnit
が該当
- Leaf: ツリー構造の末端要素を表現するクラス
- このコードでは
Employee
が該当
- このコードでは
- Composite: 子要素を持つ集合を表現するクラス
- このコードでは
Department
が該当
- このコードでは
2. 主なクラスとその役割
OrganizationUnit
- 共通インターフェース
getName
とprint
メソッドを定義し、Employee
とDepartment
の共通操作を提供
Employee
Leaf
(末端要素)を表現- 名前を持つ個々の従業員を表し、
print
メソッドで自身の名前を出力。
Department
Composite
(集合)を表現。- 部署名とその下に属するメンバー(
OrganizationUnit
)を管理。 add
メソッドで子要素を追加し、print
メソッドで自身と子要素を再帰的に出力。
3. UML クラス図
4. Composite パターンの利点
- 統一的な操作:
OrganizationUnit
インターフェースを通じて、Employee
とDepartment
を同一視して操作可能 - 再帰的な構造: 部署の中にさらに部署を持つような階層構造を簡潔に表現できる
- 拡張性: 新しい種類の要素を追加する場合も、
OrganizationUnit
を実装するだけで対応可能
この設計は、階層的なデータ構造を扱う際に非常に有効であり、組織図やファイルシステムなどの実装に適している