C++
 Computer >> コンピューター >  >> プログラミング >> C++

C++で学ぶコンポジットパターン(複合デザインパターン)の基礎と実装例

コンポジットパターン(Composite Pattern)は、複数のオブジェクトからなるグループを、あたかも単一のオブジェクトであるかのように扱いたい場面で活用されるデザインパターンです。

このパターンでは、オブジェクトを木構造(ツリー構造)として組み立てることで、「部分」と「全体」の両方の階層を一貫した形で表現できます。オブジェクト群のツリー構造を生成するパターンであるため、GoFデザインパターンの分類では「構造に関するパターン(Structural Patterns)」に属します。

コンポジットパターンの基本概念

コンポジットパターンでは、自分自身と同じ型のオブジェクト群を内部に保持するクラスを作成します。このクラスは、保持しているオブジェクト群に対して追加・削除といった操作を行うためのメソッドを提供します。

これにより、利用側のコードは「単一のオブジェクト」と「オブジェクトの集合」を区別することなく、共通のインターフェースを通じて統一的に扱えるようになります。

以下の例では、組織における従業員の階層構造を題材に、コンポジットパターンの適用イメージを示します。

C++で学ぶコンポジットパターン(複合デザインパターン)の基礎と実装例

図からわかるように、Composite(複合体)クラスとLeaf(葉)クラスは、どちらもComponent(構成要素)インターフェースを実装しています。ここで重要なのはCompositeクラスです。合成関係(composition)で示されているとおり、このクラス自身もComponentオブジェクトを内部に保持しています。

C++によるサンプルコード

ここでは、ページ(Page)とそのコピー(Copy)を例に、C++での実装を紹介します。Pageクラスがリーフ(末端の要素)の役割を、Copyクラスがコンポジット(複合体)の役割を担っています。

#include <iostream>
#include <vector>
using namespace std;

// Component(構成要素):共通のインターフェース
class PageObject {
public:
    virtual void addItem(PageObject a) { }
    virtual void removeItem() { }
    virtual void deleteItem(PageObject a) { }
};

// Leaf(葉):末端の要素
class Page : public PageObject {
public:
    void addItem(PageObject a) {
        cout << "Item added into the page" << endl;
    }
    void removeItem() {
        cout << "Item Removed from page" << endl;
    }
    void deleteItem(PageObject a) {
        cout << "Item Deleted from Page" << endl;
    }
};

// Composite(複合体):子要素を保持する
class Copy : public PageObject {
    vector<PageObject> copyPages;
public:
    void AddElement(PageObject a) {
        copyPages.push_back(a);
    }
    void addItem(PageObject a) {
        cout << "Item added to the copy" << endl;
    }
    void removeItem() {
        cout << "Item removed from the copy" << endl;
    }
    void deleteItem(PageObject a) {
        cout << "Item deleted from the copy";
    }
};

int main() {
    Page p1;
    Page p2;
    Copy myCopy;

    myCopy.AddElement(p1);
    myCopy.AddElement(p2);

    myCopy.addItem(p1);
    p1.addItem(p2);

    myCopy.removeItem();
    p2.removeItem();

    return 0;
}

実行結果

Item added to the copy
Item added into the page
Item removed from the copy
Item Removed from page

このように、Copy(コンポジット)とPage(リーフ)はどちらも同じPageObjectインターフェースを共有しているため、呼び出し側は両者を区別せずに同じメソッドで操作できます。「個」と「集合」を透過的に扱えることが、コンポジットパターンの最大の利点といえます。


  1. C++で数字パターンを出力するプログラムの作成方法

    はじめにこの記事では、C++を使って特定の数字パターンを出力するプログラムについて詳しく解説します。今回の課題は、ループ構造(for文)を活用して、以下のようなピラミッド状の数字パターンをコンソールに出力することです。 1 232 34543 4567654 567898765パターンの特徴このパターンには以下のような規則性があります。n行目は数字nから始まり、1ずつ増加しながら中央まで進みます中央を過ぎたら、今度は1ずつ減少しながら元の数字まで戻ります各行の先頭には、行番号に応じた数の空白が出力されますサンプルコード#include<bits/stdc++.h>

  2. C++のシングルトンデザインパターンをわかりやすく解説!実装例とスレッドセーフな書き方

    シングルトンパターンとは シングルトンデザインパターンは、あるクラスのインスタンス生成を1つのオブジェクトだけに制限するソフトウェア設計パターンです。システム全体の動作を1つのオブジェクトで一元管理したい場合に特に有効です。 代表的な使用例として、ファイルへログを出力するロガーが挙げられます。ロガーのインスタンスが複数存在すると、同じファイルへの同時書き込みによる競合やログの分散といった問題が発生する可能性があります。そこでシングルトンクラスを利用すれば、ロガーを確実に1つだけに保つことができます。 基本的な実装例 次のコードは、C++でシングルトンクラスを実装した例です。 #include