Чистый способ использования базового класса шаблона для устранения избыточности в производных классах для фабричного класса - PullRequest
0 голосов
/ 17 мая 2018

Я пытаюсь создать абстрактный шаблон фабрики, где у меня есть две фабрики, давайте назовем их factoryA и factoryB.Я буду использовать struct вместо класса, чтобы сохранить некоторую типизацию.

Для некоторого семейства унаследованных классов давайте начнем с некоторого класса A,

struct A
{
  // ...
};

struct derivedA1 : public A
{
  // ...
};

struct derivedA2 : public derivedA1
{
  // ...
};

Теперь позвольте, в целях иллюстрации, сделатьто же самое с другим классом B.

struct B
{
  // ...
};

struct derivedB1 : public B
{
  // ...
};

struct derivedB2 : public derivedB1
{
  // ...
};

Так что для этих классов я пытаюсь создать шаблон фабрики как таковой (заметьте, на моей работе мы используем собственную обработку ошибок, я буду вызывать error_handle_t, реализация которой должнане имеет значения):

struct factoryA
{
    std::map<int, std::shared_ptr<A> > myMap;

    factoryA()
    {
        // setup values to search against
        myMap[0] = std::make_shared<A>();
        myMap[1] = std::make_shared<derivedA1>();
        myMap[2] = std::make_shared<derivedA2>();

        //...room for more
    }

    error_handle_t make_object(int key, std::shared_ptr<A>& object)
    {
        object = myMap[key];
        return ...
    }
};

struct factoryB
{
    std::map<int, std::shared_ptr<B> > myMap;

    factoryB()
    {
        // setup values to search against
        myMap[0] = std::make_shared<B>();
        myMap[1] = std::make_shared<derivedB1>();
        myMap[2] = std::make_shared<derivedB2>();
        //...room for more
    }

    error_handle_t make_object(int key, std::shared_ptr<B>& object)
    {
        object = myMap[key];
        return ...
    }
};

Казалось бы, абстрактный интерфейсный класс мог бы быть подходящим базовым классом, но возвращаемые типы различны для каждой фабрики.И у классов A и B нет общего базового класса между ними, чтобы сделать эту работу «красиво», поэтому я не могу сделать

error_handle_t make_object(int key, std::shared_ptr<base_for_A_and_B>& object) = 0;

, но вышеперечисленные фабрики кажутся довольно стандартными и могут быть почтипараметризовано так:

template <typename T>
struct base
{
    std::map<int, std::shared_ptr<T> > myMap;

    error_handle_t make_object(int key, std::shared_ptr<T>& object)
    {
        object = myMap[key];
        return ...

    }
};

Согласно Переопределить член шаблона в интерфейсе , я не могу сделать класс шаблона виртуальным, чтобы он был абстрактным классом.

Ноесли мы можем предположить, что «алгоритм» make_object такой же.Я читал в Интернете, что это может быть служебный класс, такой, что

struct factoryA : private base<A>
{
    std::map<int, std::shared_ptr<A> > myMap;

    error_handle_t make_object(int key, std::shared_ptr<A>& object)
    {
        ...
        object = myMap[key];
        return ...
    }
};

Но я не переопределяю базу шаблонов, а просто использую ее как вспомогательную функцию.На самом деле не решает, чего я хочу достичь.

Конечная цель состояла в том, чтобы создать абстрактную фабрику, такую, чтобы

struct factories
{
    template <typename T>
    error_handle_t create(int key, shared_ptr<T>& object)
    {
        object = make_shared<T>()->make_object(key)
        return ...;
    }
};

вместо создания того же объекта без общего базового класса.

struct factories
{
    // Initialize in ctor which I didn't include here
    factoryA concrete_factoryA;
    factoryB concrete_factoryB;

    error_handle_t createA(int key, shared_ptr<A>& object)
    {
       object = concrete_factoryA.make_object(key);
       return ...;
    }

    error_handle_t createB(int key, shared_ptr<B>& object)
    {
       object = concrete_factoryB.make_object(key);
       return ...;
    }
};

Итак, я должен создать метод create столько фабрик, сколько он содержит, без шаблонов рычагов и выводов типа каким-то чистым способом.Мысли или рекомендации?

использование, которое я хотел:

factories l_factories;
shared_ptr<A> a_ptr;
shared_ptr<B> b_ptr;

l_factories.create(0, a_ptr);
l_factories.create(1, b_ptr);

против того, что у меня есть:

factories l_factories;
shared_ptr<A> a_ptr;
shared_ptr<B> b_ptr;

l_factories.createA(0, a_ptr);
l_factories.createB(1, b_ptr);

Ответы [ 2 ]

0 голосов
/ 18 мая 2018

Вы, вероятно, хотите что-то вроде:

template <typename T>
struct factory
{
    error_handle_t create(int key, shared_ptr<T>& object)
    {
        object = make_shared<T>()->make_object(key)
        return ...;
    }
};

template <typename ... Facts>
struct factories : Facts...
{
    using Facts::create...; // C++17, but can be done in C++11 with recursion
};

using factoryA = factory<A>;
using factoryB = factory<B>;
using MyFactory = factories<factoryA, factoryB>;

В C ++ 11 factories будет:

template <typename ... Facts> // Main declaration
struct factories {}; // Empty case

template <typename Fact>
struct factories<Fact> : Fact{};

template <typename Fact, typename ... Facts>
struct factories<Fact, Facts...> : Fact, factories<Facts...>
{
    using Fact::create;
    using factories<Facts...>::create;
};

, а затем

MyFactory l_factories;
shared_ptr<A> a_ptr;
shared_ptr<B> b_ptr;

l_factories.create(0, a_ptr);
l_factories.create(1, b_ptr);
0 голосов
/ 18 мая 2018

Честно говоря, я не уверен, к чему вы клоните ... Вероятно, это должен быть комментарий, а не предлагаемый ответ, но это единственный известный мне способ написания правильно отформатированного кода.Пожалуйста, извините меня.

Это предложение заставляет меня думать, что вы ищете что-то вроде:

template<typename T>
struct factory<T>;

template<>
struct factory<A>
{
   std::shared_ptr<A> make_object()
   {
     // ...
   }

}; 

template<>
struct factory<B>
{
    std::shared_ptr<B> make_object()
    {
      // ...
    }
};

это звучит?Я не могу описать, какова роль производных классов.

...