Composite パターン
表示
Composite パターン(コンポジット・パターン)とは、GoF (Gang of Four; 4人のギャングたち) によって定義された デザインパターンの1つである。「構造に関するパターン」に属する。Composite パターンを用いるとディレクトリとファイルなどのような、木構造を伴う再帰的なデータ構造を表すことができる。
Composite パターンにおいて登場するオブジェクトは、「枝」と「葉」であり、これらは共通のインターフェースを実装している。そのため、枝と葉を同様に扱えるというメリットがある。
クラス図
[編集]Composite パターンのクラス図を以下に挙げる。
利用例
[編集]Composite パターンを用いてディレクトリ構造を表すJavaプログラムの例を示す。 このプログラムは、
- 枝を表すクラス : Folderクラス
- 葉を表すクラス : Fileクラス
- 共通インタフェース : FileInterfaceインタフェース
- 実行例を示すためのクラス : DirectoryUserクラス
から構成される。
import java.util.ArrayList;
import java.util.List;
interface FileInterface {
public void defaultMethod(int depth);
public List<FileInterface> getChildren();
public boolean addComponent(FileInterface c);
public boolean removeComponent(FileInterface c);
}
class File implements FileInterface {
private String name;
public File(String name) {
this.name = name;
}
public void defaultMethod(int depth) {
for (int i = 0; i < depth; i++) System.out.print(" ");
System.out.println("file:" + this.name);
}
public List<FileInterface> getChildren() { return null; }
public boolean addComponent(FileInterface c) { return false; }
public boolean removeComponent(FileInterface c) { return false; }
}
class Folder implements FileInterface {
private String name;
private List<FileInterface> fileList = new ArrayList<FileInterface>();
public Folder(String name) { this.name = name; }
public void defaultMethod(int depth) {
for (int i = 0; i < depth; i++)
System.out.print(" ");
System.out.println("folder:" + name);
for (FileInterface file : fileList) {
file.defaultMethod(depth + 1);
}
}
public List<FileInterface> getChildren() { return this.fileList; }
public boolean addComponent(FileInterface c) { return this.fileList.add(c); }
public boolean removeComponent(FileInterface c) { return this.fileList.remove(c); }
}
public class DirectoryUser {
public static void main(String [] args){
FileInterface root = new Folder("root");
FileInterface usr = new Folder("usr");
FileInterface var = new Folder("var");
FileInterface home = new Folder("home");
FileInterface user1 = new Folder("user1");
FileInterface file1 = new File("file1");
root.addComponent(usr);
usr.addComponent(var);
root.addComponent(home);
home.addComponent(user1);
user1.addComponent(file1);
root.defaultMethod(0);
}
}
実行結果
folder:root
folder:usr
folder:var
folder:home
folder:user1
file:file1
注意事項
[編集]Composite パターンを用いる際には、データ構造がきちんと木構造を保つようにしなければならない。
親子関係が循環してしまった場合、Component#operation()
を実行した際に無限ループに陥るからである。
例えば、利用例のソースコードを書き換えた以下のプログラムは、処理が
dir1.defaultMethod(0);
の行に達した時に、無限に出力し続けてしまう。
public class LoopExample {
public static void main(String [] args){
FileInterface dir1 = new Folder("dir1");
FileInterface dir2 = new Folder("dir2");
FileInterface dir3 = new Folder("dir3");
dir1.addComponent(dir2);
dir2.addComponent(dir3);
dir3.addComponent(dir1);
dir1.defaultMethod(0);
}
}
関係するパターン
[編集]- Interpreter パターン
- 文法表現が Composite パターンとなる場合が多い。