1. 序章

このクイックチュートリアルでは、Javaの複合デザインパターンを紹介します。

構造とその使用目的について説明します。

2. 構造

複合パターンは、個々のオブジェクトとオブジェクトの構成、または「複合」を同じように処理できるようにすることを目的としています。 

これは、基本タイプを継承するタイプで構成されるツリー構造と見なすことができ、オブジェクトの単一の部分または階層全体を表すことができます。

パターンを次のように分解できます。

  • コンポーネント–コンポジション内のすべてのオブジェクトの基本インターフェイスです。 これは、子コンポジットを管理するための共通メソッドを持つインターフェースまたは抽象クラスのいずれかである必要があります。
  • リーフ–基本コンポーネントのデフォルトの動作を実装します。 他のオブジェクトへの参照は含まれていません。
  • コンポジット–リーフ要素があります。 基本コンポーネントメソッドを実装し、子関連の操作を定義します。
  • クライアント–基本コンポーネントオブジェクトを使用して構成要素にアクセスできます。

3. 実例

それでは、実装について詳しく見ていきましょう。 会社の部門の階層構造を構築したいとします。

3.1. 基本コンポーネント

コンポーネントオブジェクトとして、単純なDepartmentインターフェイスを定義します。

public interface Department {
    void printDepartmentName();
}

3.2. 葉

リーフコンポーネントについて、財務部門と営業部門のクラスを定義しましょう。

public class FinancialDepartment implements Department {

    private Integer id;
    private String name;

    public void printDepartmentName() {
        System.out.println(getClass().getSimpleName());
    }

    // standard constructor, getters, setters
}

2番目のリーフクラスSalesDepartment、も同様です。

public class SalesDepartment implements Department {

    private Integer id;
    private String name;

    public void printDepartmentName() {
        System.out.println(getClass().getSimpleName());
    }

    // standard constructor, getters, setters
}

どちらのクラスも、基本コンポーネントから printDepartmentName()メソッドを実装し、それぞれのクラス名を出力します。

また、リーフクラスであるため、他のDepartmentオブジェクトは含まれていません。

次に、複合クラスも見てみましょう。

3.3. 複合要素

複合クラスとして、HeadDepartmentクラスを作成しましょう。

public class HeadDepartment implements Department {
    private Integer id;
    private String name;

    private List<Department> childDepartments;

    public HeadDepartment(Integer id, String name) {
        this.id = id;
        this.name = name;
        this.childDepartments = new ArrayList<>();
    }

    public void printDepartmentName() {
        childDepartments.forEach(Department::printDepartmentName);
    }

    public void addDepartment(Department department) {
        childDepartments.add(department);
    }

    public void removeDepartment(Department department) {
        childDepartments.remove(department);
    }
}

これは、Departmentコンポーネントのコレクションと、リストに要素を追加および削除するためのメソッドを保持する複合クラスです。

複合printDepartmentName()メソッドは、リーフ要素のリストを反復処理し、各要素に適切なメソッドを呼び出すことによって実装されます。

4. テスト

テストの目的で、CompositeDemoクラスを見てみましょう。

public class CompositeDemo {
    public static void main(String args[]) {
        Department salesDepartment = new SalesDepartment(
          1, "Sales department");
        Department financialDepartment = new FinancialDepartment(
          2, "Financial department");

        HeadDepartment headDepartment = new HeadDepartment(
          3, "Head department");

        headDepartment.addDepartment(salesDepartment);
        headDepartment.addDepartment(financialDepartment);

        headDepartment.printDepartmentName();
    }
}

まず、財務部門と営業部門の2つのインスタンスを作成します。 その後、本社部門をインスタンス化し、以前に作成したインスタンスをそれに追加します。

最後に、 printDepartmentName()合成メソッドをテストできます。 予想どおり、出力には、各リーフコンポーネントのクラス名が含まれています。

SalesDepartment
FinancialDepartment

5. 結論

この記事では、コンポジットデザインパターンについて学びました。 この記事では、主要な構造を強調し、実際の例を通じて使用法を示しています。

いつものように、完全なコードはGithubプロジェクトで入手できます。