Composite パターン (個々のオブジェクトと合成したオブジェクトを同一視することにより, 再帰的な構造を表現する)

[Composite] という英単語は, [合成物] を意味する.

このパターンを適用すると, [容器] と [中身] を同一視することができ, 再帰的な構造の取り扱いを容易にする.

例えば, ファイルシステムで言うと, [容器] が [フォルダ] で, [中身] が [ファイル], [サブフォルダ] を意味する. 同一視できるとは, 対象となるオブジェクトが [容器でも] [中身] でも同じように取り扱える (同じ名前のメソッドで処理できる) ことを意味する.

つまり, [Composite] パターンは階層構造で表現されるオブジェクトの取り扱いを容易にするパターンである.

役割

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

クラス図

Composite パターンのクラス図

_images/designpattern-composite011.gif

ソースコード

  1. Leaf.java
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
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);
    }
}
  1. Composite.java
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
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);
    }
}
  1. Component.java
1
2
3
4
5
6
7
8
public abstract class Component{
    public abstract String getName();
    protected abstract int sumValue();
    public void add(Component component) throws ComponentAddException{
	throw new ComponentAddException();
    }
    protected abstract void printTree(String path);
}
  1. ComponentAddException.java
1
2
3
4
5
6
public class ComponentAddException extends Exception{
    public ComponentAddException(){}
    public ComponentAddException(String msg){
	super(msg);
    }
}
  1. Client.java
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
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();
	}
    }
}

上記のプログラムの実行結果:

[wtopia Composite]$ java Client
+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