Composite パターン

「Composite」という英単語は、「合成物」を意味します。

このパターンを適用すると、「容器」と「中身」を同一視することができ、再帰的な構造の取扱いを容易にします。例えば、ファイルシステムで言うと、「容器」が「フォルダ」で、「中身」が「ファイル」「サブフォルダ」を意味します。同一視できるとは、対象となるオブジェクトが「容器」でも「中身」でも同じ様に取り扱える(同じ名前のメソッドで処理できる)ことを意味します。つまり、「Composite」パターンは階層構造で表現されるオブジェクトの取扱いを容易にするパターンです。


役割り

1. Leaf(葉)
「中身」を表すクラスです。
2. Composite(合成物)
「容器」を表すクラスです。内容物として、複数の「Leaf」や「Composite」の保持が可能です。「Component」を実装したオブジェクトに対して再帰処理を行います。
3. Component(部品)
「Leaf」と「Composite」を同一視するため(同じメソッド名)のインタフェースを定義します。
4. ComponentAddException(追加例外)
追加処理の例外を表します。
5. Client(依頼者)
このパターンで構成されたオブジェクトを利用し、処理を行います。

▲PageTop

クラス図

Compositeパターンのクラス図

Compositeパターン クラス図

▲PageTop

サンプル

ソースコード

1. Leaf.java

public class Leaf extends Component {
    private String name;
    private int value;
    public Leaf(String name, int value) {
        this.name = name;
        this.value = value;
    }
    public String getName() {
    return name;
    }
    protected int sumValue() {
        System.out.println(" + " + value);
        return value;
    }
    protected void printTree(String path) {
        System.out.println(path + "-" + name);
    }
}

2. Composite.java

import java.util.List;
import java.util.ArrayList;
import java.util.Iterator;

public class Composite extends Component {
    private String name;
    private List<Component> components = new ArrayList<Component>();
    public Composite(String name) {
        this.name = name;
    }
    public String getName() {
        return name;
    }
    protected void printTree(String path) {
        System.out.println(path + "-" + name);
        Iterator<Component> it = components.iterator();
        while (it.hasNext()){
            it.next().printTree(path + "-" + name);
        }
    }
    protected int sumValue() {
        int sum = 0;
        Iterator<Component> it = components.iterator();
        while (it.hasNext()){
            sum += it.next().sumValue();
        }
        return sum;
    }
    public void add(Component component) throws ComponentAddException {
        components.add(component);
    }
}

3. Component.java

public abstract class Component {
    public abstract String getName();
    protected abstract int sumValue();
    public void add(Component component) throws ComponentAddException {
        /** この「add」メソッドはサブクラスで実装されない(「Leaf」)可能性があるため、
            デフォルトの処理としては、例外を発生させるようにしておきます。 */
        throw new ComponentAddException();
    }
    protected abstract void printTree(String path);
}

4. ComponentAddException.java

public class ComponentAddException extends Exception {
    public ComponentAddException() {}
    public ComponentAddException(String msg) {
        super(msg);
    }
}

5. Client.java

public class Client {
    public static void main(String[] args) {
        Composite comp1 = new Composite("A");
        Composite comp11 = new Composite("AB");
        Composite comp12 = new Composite("AC");
        Composite comp13 = new Composite("AD");
        Composite comp111 = new Composite("ABE");
        Composite comp112 = new Composite("ABF");
        try {
            comp1.add(comp11);
            comp1.add(comp12);
            comp1.add(comp13);
            comp11.add(comp111);
            comp11.add(comp112);
            comp11.add(new Leaf("a", 1));
            comp11.add(new Leaf("b", 2));
            comp11.add(new Leaf("c", 3));
            comp13.add(new Leaf("d", 4));
            comp112.add(new Leaf("e", 5));
            int sum = comp1.sumValue();
            System.out.println("----");
            System.out.println("  " + sum);
            System.out.println("");
            comp1.printTree("");
        } catch (ComponentAddException e) {
            e.printStackTrace();
        }
    }
}

実行結果

C:\sample\desin_pattern\composite>javac Client.java [Enter]

C:\sample\desin_pattern\composite>java Client [Enter]
 + 5
 + 1
 + 2
 + 3
 + 4
----
  15

-A
-A-AB
-A-AB-ABE
-A-AB-ABF
-A-AB-ABF-e
-A-AB-a
-A-AB-b
-A-AB-c
-A-AC
-A-AD
-A-AD-d
        

▲PageTop