Composite パターン

出典: フリー百科事典『ウィキペディア(Wikipedia)』
移動: 案内検索

Composite パターン(コンポジット・パターン)とは、GoF(Gang of Four; 4人のギャングたち)によって定義された デザインパターンの1つである。「構造に関するパターン」に属する。Composite パターンを用いるとディレクトリファイルなどのような、木構造を伴う再帰的データ構造を表すことができる。

Composite パターンにおいて登場するオブジェクトは、「枝」と「葉」であり、これらは共通のインターフェースを実装している。そのため、枝と葉を同様に扱えるというメリットがある。

クラス図[編集]

Composite パターンのクラス図を以下に挙げる。

Composite UML class diagram (fixed).svg

利用例[編集]

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 パターンとなる場合が多い。

関連項目[編集]