コンポジットパターンの利用方法と実装例

composite-pattern

今日のトピックは「コンポジットパターンの利用方法」です。コンポジットパターンは、再帰的な構造を持つオブジェクト群を個別のオブジェクトと同様に扱えるようにするデザインパターンです。つまり、個々のオブジェクトと、複数のオブジェクトをグループ化したオブジェクトを統一的に扱うことができます。ツリー構造を持つデータを扱う際に非常に有効です。

目次

基本概念の説明

コンポジットパターン (Composite Pattern)

コンポジットパターンは、「部分 – 全体」の階層構造を表現するためのデザインパターンです。このパターンを使用すると、個々のオブジェクトと複数のオブジェクトをグループ化したオブジェクトを同じインターフェースで扱うことができ、再帰的な構造を簡潔に表現できます。

各言語でのサンプルコード

Python

class Component:
    def operation(self):
        pass

class Leaf(Component):
    def operation(self):
        return "Leaf"

class Composite(Component):
    def __init__(self):
        self._children = []

    def add(self, component):
        self._children.append(component)

    def remove(self, component):
        self._children.remove(component)

    def operation(self):
        results = []
        for child in self._children:
            results.append(child.operation())
        return f"Branch({'+'.join(results)})"

# 使用
leaf1 = Leaf()
leaf2 = Leaf()
composite = Composite()
composite.add(leaf1)
composite.add(leaf2)

print(composite.operation())  # Branch(Leaf+Leaf)

C#

using System;
using System.Collections.Generic;

public abstract class Component {
    public abstract string Operation();
}

public class Leaf : Component {
    public override string Operation() {
        return "Leaf";
    }
}

public class Composite : Component {
    protected List<Component> _children = new List<Component>();

    public void Add(Component component) {
        _children.Add(component);
    }

    public void Remove(Component component) {
        _children.Remove(component);
    }

    public override string Operation() {
        List<string> results = new List<string>();
        foreach (var child in _children) {
            results.Add(child.Operation());
        }
        return $"Branch({string.Join("+", results)})";
    }
}

// 使用例
public class Program {
    public static void Main() {
        Leaf leaf1 = new Leaf();
        Leaf leaf2 = new Leaf();
        Composite composite = new Composite();
        composite.Add(leaf1);
        composite.Add(leaf2);

        Console.WriteLine(composite.Operation());  // Branch(Leaf+Leaf)
    }
}

C++

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

class Component {
public:
    virtual std::string operation() const = 0;
    virtual ~Component() {}
};

class Leaf : public Component {
public:
    std::string operation() const override {
        return "Leaf";
    }
};

class Composite : public Component {
    std::vector<Component*> children;
public:
    void add(Component* component) {
        children.push_back(component);
    }

    void remove(Component* component) {
        children.erase(std::remove(children.begin(), children.end(), component), children.end());
    }

    std::string operation() const override {
        std::string result = "Branch(";
        for (size_t i = 0; i < children.size(); ++i) {
            result += children[i]->operation();
            if (i != children.size() - 1) {
                result += "+";
            }
        }
        return result + ")";
    }
};

// 使用例
int main() {
    Leaf leaf1, leaf2;
    Composite composite;
    composite.add(&leaf1);
    composite.add(&leaf2);

    std::cout << composite.operation() << std::endl;  // Branch(Leaf+Leaf)
    return 0;
}

Java

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

abstract class Component {
    public abstract String operation();
}

class Leaf extends Component {
    @Override
    public String operation() {
        return "Leaf";
    }
}

class Composite extends Component {
    private List<Component> children = new ArrayList<>();

    public void add(Component component) {
        children.add(component);
    }

    public void remove(Component component) {
        children.remove(component);
    }

    @Override
    public String operation() {
        StringBuilder result = new StringBuilder("Branch(");
        for (int i = 0; i < children.size(); i++) {
            result.append(children.get(i).operation());
            if (i != children.size() - 1) {
                result.append("+");
            }
        }
        return result.append(")").toString();
    }
}

// 使用例
public class Main {
    public static void main(String[] args) {
        Leaf leaf1 = new Leaf();
        Leaf leaf2 = new Leaf();
        Composite composite = new Composite();
        composite.add(leaf1);
        composite.add(leaf2);

        System.out.println(composite.operation());  // Branch(Leaf+Leaf)
    }
}

JavaScript

class Component {
    operation() {
        throw new Error("This method should be overridden!");
    }
}

class Leaf extends Component {
    operation() {
        return "Leaf";
    }
}

class Composite extends Component {
    constructor() {
        super();
        this.children = [];
    }

    add(component) {
        this.children.push(component);
    }

    remove(component) {
        this.children = this.children.filter(child => child !== component);
    }

    operation() {
        return `Branch(${this.children.map(child => child.operation()).join('+')})`;
    }
}

// 使用例
const leaf1 = new Leaf();
const leaf2 = new Leaf();
const composite = new Composite();
composite.add(leaf1);
composite.add(leaf2);

console.log(composite.operation());  // Branch(Leaf+Leaf)

各言語の解説

言語コンポジットパターンの実装方法特徴
Pythonクラスとリストを使用してコンポーネントを管理シンプルで柔軟、再帰的構造を直感的に実装可能
C#抽象クラスとジェネリックコレクションを使用強力な型安全性と拡張性、オブジェクト指向の設計が容易
C++仮想メソッドとポインタを使用してコンポーネントを管理高速で効率的、複雑なツリー構造を直接的に表現可能
Java抽象クラスとリストを使用してコンポーネントを管理強力なオブジェクト指向機能と堅牢性、Javaの標準APIと統合が容易
JavaScriptクラスと配列を使用してコンポーネントを管理柔軟でシンプル、フロントエンドやNode.js環境に最適

まとめ

コンポジットパターンを利用することで、ツリー構造を持つデータを効率的に管理し、統一的に操作することが可能です。個々のオブジェクトとグループ化されたオブジェクトを同じように扱えるため、コードの柔軟性と再利用性が向上します。次回は「ブリッジパターンの利用方法」について学習しましょう。

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

コメント

コメントする

目次