コンポジットパターン
コンポジットパターン(Composite Pattern)は、部分全体パターンとも呼ばれ、一組の類似したオブジェクトを単一のオブジェクトとして扱うためのものです。コンポジットパターンはツリー構造に基づいてオブジェクトを組み合わせ、部分および全体の階層を表現します。このタイプのデザインパターンは構造型パターンに属し、オブジェクトグループのツリー構造を作成します。
このパターンは、自身のオブジェクトグループを含むクラスを作成します。このクラスは、同じオブジェクトグループを変更する方法を提供します。
以下の例を通じて、コンポジットパターンの使用方法を説明します。この例では、組織内の従業員の階層構造を示します。
紹介
意図
オブジェクトをツリー構造に組み合わせて「部分-全体」の階層構造を表現します。コンポジットパターンにより、ユーザーは単一のオブジェクトと複合オブジェクトを一貫して使用できます。
主に解決する問題
- ツリー構造内のオブジェクトが単一オブジェクトであっても複合オブジェクトであっても、その処理を簡素化します。
- クライアントコードと複雑な要素の内部構造をデカップリングし、クライアントがすべてのタイプのノードを統一的に処理できるようにします。
使用シーン
- ファイルシステムや組織構造など、オブジェクトの階層構造を表現する必要がある場合。
- クライアントコードがツリー構造内のすべてのオブジェクトを一貫した方法で処理できるようにしたい場合。
実装方法
- 統一インターフェース:すべてのオブジェクト(枝と葉)が実装するインターフェースを定義します。
- 複合構造:枝オブジェクトはインターフェースの参照リストを保持し、これらの参照は葉または枝にすることができます。
主要コード
- Componentインターフェース:すべてのオブジェクトが実装しなければならない操作を定義します。
- Leafクラス:Componentインターフェースを実装し、ツリー内の葉ノードを表します。
- Compositeクラス:同じくComponentインターフェースを実装し、他のComponentオブジェクトの集合を含みます。
応用例
- 算術式:オペランド、演算子、および部分式からなるツリー構造を構築します。
- GUIコンポーネント:JavaのAWTおよびSwingライブラリでは、コンテナ(Panelなど)は他のコンポーネント(ボタンやチェックボックスなど)を含むことができます。
利点
- クライアントコードの簡素化:クライアントはすべてのタイプのノードを統一的に処理できます。
- 拡張が容易:新しい葉タイプや枝タイプを簡単に追加できます。
欠点
- 依存性逆転の原則に違反する:コンポーネントの宣言がインターフェースではなく具象クラスに基づいているため、コードの柔軟性が低下する可能性があります。
使用上のアドバイス
- 設計時には、具象クラスではなくインターフェースを優先的に使用して、システムの柔軟性と保守性を高めます。
- ファイルシステムや組織構造など、複雑なツリー構造を処理する必要があるシーンに適しています。
注意事項
- 実装時には、すべてのコンポーネントが統一されたインターフェースに従うようにして、一貫性を維持します。
- ファクトリーパターンを使用して異なるタイプのコンポーネントを作成し、コンポーネントの作成ロジックをさらに分離することを検討してください。
構造
コンポジットパターンの中心的な役割は次のとおりです:
コンポーネント(Component):
- 組み合わせ内のすべてのオブジェクトの共通インターフェースを定義します。抽象クラスまたはインターフェースにすることができます。子コンポーネントの追加、削除、取得など、子コンポーネントにアクセスして管理するためのメソッドを宣言します。
葉ノード(Leaf):
- 組み合わせ内の葉ノードオブジェクトを表します。葉ノードには子ノードがありません。コンポーネントインターフェースのメソッドを実装しますが、通常は子コンポーネントを含みません。
複合ノード(Composite):
- 組み合わせ内の複合オブジェクトを表します。複合ノードは子ノードを含むことができ、子ノードは葉ノードでも他の複合ノードでも構いません。コンポーネントインターフェースのメソッドを実装し、子コンポーネントを管理するメソッドも含みます。
クライアント(Client):
- コンポーネントインターフェースを通じて複合構造と対話します。クライアントは葉ノードと複合ノードを区別する必要がなく、全体と部分を一貫して扱うことができます。
実装
クラスがありますEmployee、このクラスは複合モデルクラスとして扱われます。CompositePatternDemoクラスはEmployeeクラスを使用して部門の階層構造を追加し、すべての従業員を出力します。
ステップ 1
作成Employeeクラス、このクラスはEmployeeオブジェクトのリストを持ちます。
Employee.java
import java.util.ArrayList;
import java.util.List;
public class Employee {
private String name;
private String dept;
private int salary;
private List<Employee> subordinates;
//コンストラクタ
public Employee(String name,String dept, int sal) {
this.name = name;
this.dept = dept;
this.salary = sal;
subordinates = new ArrayList<Employee>();
}
public void add(Employee e) {
subordinates.add(e);
}
public void remove(Employee e) {
subordinates.remove(e);
}
public List<Employee> getSubordinates(){
return subordinates;
}
public String toString(){
return ("Employee :[ Name : "+ name
+", dept : "+ dept + ", salary :"
+ salary+" ]");
}
}
ステップ 2
使用Employeeクラスを使用して、従業員の階層構造を作成し、出力します。
CompositePatternDemo.java
public class CompositePatternDemo {
public static void main(String[] args) {
Employee CEO = new Employee("John","CEO", 30000);
Employee headSales = new Employee("Robert","Head Sales", 20000);
Employee headMarketing = new Employee("Michel","Head Marketing", 20000);
Employee clerk1 = new Employee("Laura","Marketing", 10000);
Employee clerk2 = new Employee("Bob","Marketing", 10000);
Employee salesExecutive1 = new Employee("Richard","Sales", 10000);
Employee salesExecutive2 = new Employee("Rob","Sales", 10000);
CEO.add(headSales);
CEO.add(headMarketing);
headSales.add(salesExecutive1);
headSales.add(salesExecutive2);
headMarketing.add(clerk1);
headMarketing.add(clerk2);
//組織のすべての従業員を出力します
System.out.println(CEO);
for (Employee headEmployee : CEO.getSubordinates()) {
System.out.println(headEmployee);
for (Employee employee : headEmployee.getSubordinates()) {
System.out.println(employee);
}
}
}
}
ステップ 3
プログラムを実行すると、出力結果は次のとおりです:
Employee :[ Name : John, dept : CEO, salary :30000 ] Employee :[ Name : Robert, dept : Head Sales, salary :20000 ] Employee :[ Name : Richard, dept : Sales, salary :10000 ] Employee :[ Name : Rob, dept : Sales, salary :10000 ] Employee :[ Name : Michel, dept : Head Marketing, salary :20000 ] Employee :[ Name : Laura, dept : Marketing, salary :10000 ] Employee :[ Name : Bob, dept : Marketing, salary :10000 ]その他の拡張