Composite パターンとは
Composite パターンは、GoF(Gang of Four)によって定義されたデザインパターンの一つで、「構造に関するパターン」に分類されます。このパターンは、
ディレクトリとファイルのように、木構造を伴う再帰的な
データ構造を扱う際に非常に有効です。
概要
Composite パターンでは、オブジェクトを「枝(Composite)」と「葉(Leaf)」に分類し、これらが共通のインターフェースを実装することで、枝と葉を均一に扱うことを可能にします。これにより、クライアントは、枝と葉を区別せずに操作できるため、複雑な
データ構造をシンプルに扱うことができます。
Composite パターンの
クラス図は以下のようになります。
mermaid
classDiagram
class Component{
<
>
+operation()
}
class Composite{
+children
+add(Component)
+remove(Component)
+operation()
}
class Leaf{
+operation()
}
Component <|-- Composite
Component <|-- Leaf
Component(コンポーネント): 枝と葉が実装すべき共通のインターフェースを定義します。`operation()`のようなメソッドを宣言します。
Composite(コンポジット): 枝を表すクラスで、`Component`インターフェースを実装し、子要素(`Component`のインスタンス)を保持します。`add()`, `remove()`などの子要素を管理するメソッドと、`operation()`を実装します。
Leaf(リーフ): 葉を表すクラスで、`Component`インターフェースを実装し、具体的な処理を行います。
利用例
以下に、Composite パターンを用いてディレクトリ構造を表すJavaプログラムの例を示します。
java
// Component インターフェース
interface FileInterface {
void defaultMethod(int indent);
}
// Leaf クラス (ファイル)
class File implements FileInterface {
private String name;
public File(String name) {
this.name = name;
}
@Override
public void defaultMethod(int indent) {
for (int i = 0; i < indent; i++) {
System.out.print(" ");
}
System.out.println("- " + name);
}
}
// Composite クラス (フォルダ)
class Folder implements FileInterface {
private String name;
private List children = new ArrayList<>();
public Folder(String name) {
this.name = name;
}
public void add(FileInterface file) {
children.add(file);
}
public void remove(FileInterface file) {
children.remove(file);
}
@Override
public void defaultMethod(int indent) {
for (int i = 0; i < indent; i++) {
System.out.print(" ");
}
System.out.println("+ " + name);
for (FileInterface file : children) {
file.defaultMethod(indent + 1);
}
}
}
// 利用例クラス
class DirectoryUser {
public static void main(String[] args) {
Folder dir1 = new Folder("dir1");
Folder dir2 = new Folder("dir2");
File file1 = new File("file1");
File file2 = new File("file2");
File file3 = new File("file3");
dir1.add(file1);
dir1.add(dir2);
dir2.add(file2);
dir2.add(file3);
dir1.defaultMethod(0);
}
}
このプログラムでは、`FileInterface`が`Component`インターフェースに相当し、`Folder`クラスが`Composite`クラスに、`File`クラスが`Leaf`クラスに相当します。
実行結果
上記のプログラムを実行すると、以下のような出力が得られます。
+ dir1
- file1
+ dir2
- file2
- file3
これは、ディレクトリ構造が正しく表現されていることを示しています。
注意事項
Composite パターンを使用する際には、データ構造がきちんと木構造を維持するように注意する必要があります。親子関係が循環してしまうと、`Component#operation()`を実行した際に無限ループに陥る可能性があります。例えば、上記の例で、`dir2`を`dir1`の子に加えるような処理を追加すると、無限ループが発生します。
関係するパターン
Interpreter パターン: 文法表現が Composite パターンとなる場合が多く、言語処理系などで利用されます。
関連項目
木構造 (データ構造))
再帰データ型
再帰呼び出し
無限ループ
Composite パターンは、柔軟で拡張性の高いシステムを構築するための強力なツールとなります。適切に利用することで、複雑なデータ構造をシンプルに管理し、コードの再利用性を高めることができます。