今日のトピックは「コンポジットパターンの利用方法」です。コンポジットパターンは、再帰的な構造を持つオブジェクト群を個別のオブジェクトと同様に扱えるようにするデザインパターンです。つまり、個々のオブジェクトと、複数のオブジェクトをグループ化したオブジェクトを統一的に扱うことができます。ツリー構造を持つデータを扱う際に非常に有効です。
目次
基本概念の説明
コンポジットパターン (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環境に最適 |
まとめ
コンポジットパターンを利用することで、ツリー構造を持つデータを効率的に管理し、統一的に操作することが可能です。個々のオブジェクトとグループ化されたオブジェクトを同じように扱えるため、コードの柔軟性と再利用性が向上します。次回は「ブリッジパターンの利用方法」について学習しましょう。
コメント