I'm trying to create an abstract factory pattern where I have two factories, lets call them factoryA and factoryB. I'll use struct instead of class to save some typing.
For some family of inherited classes, lets start with some class A,
struct A
{
// ...
};
struct derivedA1 : public A
{
// ...
};
struct derivedA2 : public derivedA1
{
// ...
};
Now let, for illustration purposes do the same thing with some other class B.
struct B
{
// ...
};
struct derivedB1 : public B
{
// ...
};
struct derivedB2 : public derivedB1
{
// ...
};
So for these classes I'm trying to create a factory pattern as so (Note at my job we use custom error handling I'll call error_handle_t whose implementation shouldn't matter):
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 ...
}
};
It would seem like an "interface" abstract class could be an appropriate base class but the return types differ for each factory. And class A and B don't have a common base class between them to make this work "nicely" like that so I can't do
error_handle_t make_object(int key, std::shared_ptr<base_for_A_and_B>& object) = 0;
but the above factories seem pretty boilerplate and could almost be parameterized as so
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 ...
}
};
According to Override template member in Interface, I can't make the template class virtual for this to be an abstract class.
But if we can assume the "algorithm" of make_object is the same. I read online that this could be a utility class such that
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 ...
}
};
But I'm not overriding the template base and just using it as a helper function. Doesn't really solve what I want to achieve.
The final goal was to have an abstract factory such that
struct factories
{
template <typename T>
error_handle_t create(int key, shared_ptr<T>& object)
{
object = make_shared<T>()->make_object(key)
return ...;
}
};
Instead of create the same object without a common base class.
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 ...;
}
};
So I have to make a create method as many factories as it contains without leverage templates and type deduction in some clean way. Thoughts or recommendations?
the usage I wanted:
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);
versus what I have:
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);