C++ 設計パターン:Factory パターンの基礎と応用

Factory パターンは、オブジェクトのインスタンス化プロセスをカプセル化する創造型デザインパターンの代表的な手法です。これにより、クライアントコードと具体的なクラスの実装間の結合度を低下させ、システムの保守性や拡張性を向上させることが可能です。

簡易工場パターン (Simple Factory)

このアプローチでは、特定のパラメータに基づいて製品クラスのインスタンスを選択する静的メソッドを提供します。ただし、新製品の追加時に既存のファクトリクラスを変更する必要があるため、オープン/クローズ原則には適合しません。

#include <iostream>
#include <memory>

// 共通基盤となる抽象クラス
class Item {
public:
    virtual ~Item() = default;
    virtual void execute() const = 0;
};

// 具体的実装 A
class Coffee : public Item {
public:
    void execute() const override {
        std::cout << "Making coffee..." << std::endl;
    }
};

// 具体的実装 B
class Tea : public Item {
public:
    void execute() const override {
        std::cout << "Boiling water for tea..." << std::endl;
    }
};

// ファクトリクラス
class BeverageCenter {
public:
    static std::unique_ptr<Item> create(int type) {
        if (type == 1) {
            return std::make_unique<Coffee>();
        } else if (type == 2) {
            return std::make_unique<Tea>();
        }
        return nullptr;
    }
};

工場メソッドパターン (Factory Method)

製品を作成するためのインターフェースを定義し、実際のインスタンス化処理をサブクラスに委譲します。各具体ファクトリは特定の製品に対応しており、新製品を追加する際にも既存コードへの影響を抑えられます。

#include <iostream>
#include <memory>

class Product {
public:
    virtual ~Product() = default;
    virtual void operation() const = 0;
};

class Creator {
public:
    virtual ~Creator() = default;
    // ファクトリメソッド
    virtual std::unique_ptr<Product> create_product() const = 0;
};

class ConcreteProductA : public Product {
public:
    void operation() const override {
        std::cout << "Executing Product A logic" << std::endl;
    }
};

class ConcreteProductB : public Product {
public:
    void operation() const override {
        std::cout << "Executing Product B logic" << std::endl;
    }
};

// 具体クリエーター A
class FactoryA : public Creator {
public:
    std::unique_ptr<Product> create_product() const override {
        return std::make_unique<ConcreteProductA>();
    }
};

// 具体クリエーター B
class FactoryB : public Creator {
public:
    std::unique_ptr<Product> create_product() const override {
        return std::make_unique<ConcreteProductB>();
    }
};

抽象工場パターン (Abstract Factory)

関連するオブジェクト群(ファミリー)を作成するインターフェースを提供します。特定の具象クラスを参照することなく、一貫したセットの製品群を生成することが可能となります。

#include <iostream>
#include <memory>

// 抽象製品族:ボタン
class Button {
public:
    virtual ~Button() = default;
    virtual void paint() const = 0;
};

// 抽象製品族:チェックボックス
class Checkbox {
public:
    virtual ~Checkbox() = default;
    virtual void paint() const = 0;
};

// 具体的な製品
class WindowsButton : public Button {
public:
    void paint() const override { std::cout << "Windows Style Button" << std::endl; }
};
class MacButton : public Button {
public:
    void paint() const override { std::cout << "Mac Style Button" << std::endl; }
};
class WindowsCheckbox : public Checkbox {
public:
    void paint() const override { std::cout << "Windows Style Checkbox" << std::endl; }
};
class MacCheckbox : public Checkbox {
public:
    void paint() const override { std::cout << "Mac Style Checkbox" << std::endl; }
};

// 抽象工場
class GuiFactory {
public:
    virtual ~GuiFactory() = default;
    virtual std::unique_ptr<Button> create_button() const = 0;
    virtual std::unique_ptr<Checkbox> create_checkbox() const = 0;
};

// 具体的な工場:Windows シリーズ
class WindowsFactory : public GuiFactory {
public:
    std::unique_ptr<Button> create_button() const override {
        return std::make_unique<WindowsButton>();
    }
    std::unique_ptr<Checkbox> create_checkbox() const override {
        return std::make_unique<WindowsCheckbox>();
    }
};

// 具体的な工場:Mac シリーズ
class MacFactory : public GuiFactory {
public:
    std::unique_ptr<Button> create_button() const override {
        return std::make_unique<MacButton>();
    }
    std::unique_ptr<Checkbox> create_checkbox() const override {
        return std::make_unique<MacCheckbox>();
    }
};

主要な利点

  • 実装詳細の隠蔽: クライアント側が具体的なインスタンス作成手順を知る必要がなく、内部構造を隔離することでモジュール性が向上します。
  • 拡張性の確保: 新しい型の追加時にファクトリ側のロジックのみを更新すれば良く、既存のクライアントコードに影響を与えずに対処できます。
  • 責務の分離: 物体の「生成」と「利用」を別々のコンポーネントが担うことで、単一責任の原則を実践しやすくします。
  • 依存関係の注入: 外部から異なる実装を提供しやすくなり、テスト容易性や可搬性が改善されます。

タグ: C++ DesignPatterns ObjectOrientedProgramming SoftwareArchitecture ModernCpp

5月21日 02:56 投稿