Categories
デザインパターン

Composite パターン

概要

コンポジットパターン(Composite Pattern)は、ソフトウェア設計パターンの一つです。このパターンは、オブジェクトの階層構造を表現し、個々のオブジェクトとオブジェクトのコレクションを同じように扱うことを可能にします。コンポジットパターンは、単一のオブジェクトと複数のオブジェクトの間に階層的な関係があり、これらを一貫して操作する必要がある場合に使用されます。

コンポジットパターンでは、以下の要素が関与します:

  1. コンポーネント(Component):単一のオブジェクトとオブジェクトのコレクションを同じように扱うための共通のインターフェースを定義します。コンポーネントは葉(Leaf)と合成(Composite)の2つの具象クラスに分類されます。
  2. 葉(Leaf):コンポーネントの末端に位置するオブジェクトを表します。葉はコンポーネントの基本要素であり、子要素を持ちません。個々の葉オブジェクトは特定の操作を実行します。
  3. 合成(Composite):コンポーネントのコンテナとしての役割を果たすオブジェクトを表します。合成は複数の子コンポーネントを持ち、それらの操作をまとめて実行したり、追加・削除・取得などの操作を提供します。

コンポジットパターンは、以下のような状況で使用されます:

  • オブジェクトのツリー構造を表現し、階層的な関係を持つ必要がある場合。
  • 個々のオブジェクトとオブジェクトのコレクションを同じように扱い、一貫性を保ちながら操作を行いたい場合。
  • クライアントが単一のオブジェクトと複数のオブジェクトを区別せずに操作したい場合。

コンポジットパターンにより、階層構造を持つオブジェクトを効果的に扱うことができます。個々のオブジェクトとグループ化されたオブジェクトを統一的に操作できるため、柔軟性や再利用性の向上が期待できます。

コード例

以下は、C++でのコンポジットパターンのコード例です。この例では、ファイルシステムを表現する階層的な構造を持つオブジェクトを作成します。

#include <iostream>
#include <string>
#include <vector>

// コンポーネントの共通インターフェース
class FileSystemComponent {
public:
    virtual void display() const = 0;
};

// 葉オブジェクト
class File : public FileSystemComponent {
private:
    std::string name;

public:
    File(const std::string& name) : name(name) {}

    void display() const override {
        std::cout << "File: " << name << std::endl;
    }
};

// 合成オブジェクト
class Directory : public FileSystemComponent {
private:
    std::string name;
    std::vector<FileSystemComponent*> components;

public:
    Directory(const std::string& name) : name(name) {}

    void addComponent(FileSystemComponent* component) {
        components.push_back(component);
    }

    void removeComponent(FileSystemComponent* component) {
        // componentsからcomponentを削除する処理
    }

    void display() const override {
        std::cout << "Directory: " << name << std::endl;
        for (const auto& component : components) {
            component->display();
        }
    }
};

int main() {
    // ファイルとディレクトリの作成
    FileSystemComponent* file1 = new File("file1.txt");
    FileSystemComponent* file2 = new File("file2.txt");
    FileSystemComponent* directory1 = new Directory("directory1");
    FileSystemComponent* directory2 = new Directory("directory2");

    // ディレクトリにファイルと別のディレクトリを追加
    static_cast<Directory*>(directory1)->addComponent(file1);
    static_cast<Directory*>(directory1)->addComponent(directory2);
    static_cast<Directory*>(directory2)->addComponent(file2);

    // ディレクトリの表示
    directory1->display();

    // メモリの解放
    delete file1;
    delete file2;
    delete directory1;
    delete directory2;

    return 0;
}

このコードでは、FileSystemComponentクラスがコンポーネントの共通インターフェースを定義しています。Fileクラスは葉オブジェクトを表し、Directoryクラスは合成オブジェクトを表します。

Directoryクラスは複数のFileSystemComponentオブジェクトを保持することができるため、addComponentremoveComponentメソッドを提供しています。displayメソッドでは、ディレクトリ名を表示し、保持しているコンポーネントを順に表示します。

main関数では、ファイルとディレクトリを作成し、ディレクトリにファイルと別のディレクトリを追加します。その後、ディレクトリの表示を行います。

コンポジットパターンにより、ファイルシステムの階層構造を柔軟に表現できます。単一のファイルとディレクトリを同じように扱い、一貫性を保ちながら操作することができます。