0

次の問題を解決する方法を見つけようとしています (実際のコードの削除バージョン、明らかなメモリ リークについて申し訳ありません)。

#include <iostream>

namespace A {
    struct Product {
        virtual void doSomething() const =0;
    };

    template<typename T>
    struct SpecialProduct : public Product {
        T t;
        SpecialProduct(T t) : t(t) {};
        virtual void doSomething() const { std::cout << "A: " << t << " does something\n"; }
    };

    struct Factory {
        template<typename T>
        Product* create(T t = T()) const { return new SpecialProduct<T>(t); }
    };
}
namespace B {
    struct Product {
        virtual void doSomething() const =0;
    };

    template<typename T>
    struct SpecialProduct : public Product {
        T t;
        SpecialProduct(T t) : t(t) {};
        virtual void doSomething() const { std::cout << "B: " << t << " does something\n"; }
    };

    struct Factory {
        template<typename T>
        Product* create(T t = T()) const { return new SpecialProduct<T>(t); }
    };
}


struct ProductType { };

template<typename T>
struct SpecialProductType : public ProductType {};

int main() {

    // I have a factory of a known type
    A::Factory f;

    // standard procedure
    A::Product* p = f.create<int>();
    p->doSomething();

    // I have a product type description from some source
    ProductType* t = /* some source */ 0;

    // How do i get a product instance of type t from f?
    // A::Product* p = f. ???
}

この場合、異なる名前空間内に、モジュールの複数の実装があります。ファクトリ パターンは、バリアントを処理するために利用されます。各モジュールは、(抽象) 製品と特殊なジェネリック バージョンを提供します。製品タイプは、同じパターンに従う均一なクラス インフラストラクチャを使用して表されます。

私の問題は、特定の製品タイプへのポインターが与えられた場合、特定のファクトリ オブジェクトから対応する特定の製品のインスタンスを生成する関数をどのように実装できるかということです。

アドバイスありがとうございます。

4

1 に答える 1

0

数日間作業した後、次の解決策を思いつきました。

#include <iostream>
#include <functional>
#include <typeinfo>
#include <typeindex>
#include <map>
#include <string>

using namespace std;

struct ProductType {
    type_index type;
    ProductType(type_index type) : type(type) {}
};

template<typename T>
struct SpecialProductType : public ProductType {
    SpecialProductType() : ProductType(typeid(T)) {}
};


template<typename Derived, typename _product_type>
struct FactoryBase {

    typedef _product_type product_type;

    map<type_index, function<product_type*()>> creators;

    template<typename T>
    void addProductType() {
        creators[typeid(T)] = [&]()->product_type* { 
            static_cast<Derived*>(this)->template create<T>(); 
        };
    }

    product_type* createForType(const ProductType& type) {
        return creators[type.type]();
    }
};  


namespace A {
    struct Product {
        virtual void doSomething() const =0;
    };

    template<typename T>
    struct SpecialProduct : public Product {
        T t;
        SpecialProduct(T t = T()) : t(t) {};
        virtual void doSomething() const { std::cout << "A: " << typeid(T).name() << " does something\n"; }
    };

    struct Factory : public FactoryBase<Factory,Product> {
        typedef Product product_type;
        template<typename T>
        Product* create() const { 
            std::cout << "A is creating a product of type " << typeid(T).name() << "\n";
                return new SpecialProduct<T>(); 
        }
    };
}
namespace B {
    struct Product {
        virtual void doSomething() const =0;
    };

    template<typename T>
    struct SpecialProduct : public Product {
        T t;
        SpecialProduct(T t = T()) : t(t) {};
        virtual void doSomething() const { std::cout << "B: " << typeid(T).name() << " does something\n"; }
    };

    struct Factory : public FactoryBase<Factory,Product> {
        typedef Product product_type;
        template<typename T>
        Product* create() const { 
            std::cout << "B is creating a product of type " << typeid(T).name() << "\n";
            return new SpecialProduct<T>(); 
        }
    };
}


int main() {

    // I have a factory of a known type
    A::Factory f;
    f.addProductType<float>();
    f.addProductType<string>();

    ProductType* tf = new SpecialProductType<float>();
    ProductType* ts = new SpecialProductType<string>();

    f.createForType(*tf)->doSomething();
    f.createForType(*ts)->doSomething();
}

基本的に、FactoryBase クラス内で作成される製品のタイプに基づいて、独自の動的ディスパッチャ テーブルを構築しています。キーはジェネリック型で、値は適切なインスタンスを作成できるファンクターです。

提示されたソリューションの欠点は、サポートされているタイプのリストを登録する必要があることですが、これは、ファクトリのコードまたは製品タイプ (オープン/クローズの原則) を変更せずに行うことができます。どのユーザー コードでも、サポートされる製品タイプのリストを動的に拡張できます。

于 2013-11-05T16:07:18.577 に答える