jeudi 17 mai 2018

Clean way to use a template base class to eliminate redundancy on derived classes for a factory class

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:

struct factoryA
{
    std::shared_ptr<A> make_object( )
    {
        ...
    }
};

struct factoryB
{
    std::shared_ptr<B> make_object()
    {
        ...
    }
};

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

std::shared_ptr<base_for_A_and_B> make_object(...) = 0;

but the above factories seem pretty boilerplate and could almost be parameterized as so

template <typename T>
struct base
{
    std::shared_ptr<T> make_object()
    {
        //...
    }
};

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::shared_ptr<A> make_object( )
    {
        ...
        return base<A>::make_object();
    }
};

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
{
    shared_ptr<base> create()
    {
        // ... didn't define concrete_factory but shouldn't matter
        // this just illustrates intent
        return concrete_factory->make_object();
    }
};

Instead of create the same object without a common base class.

struct factories
{
    shared_ptr<A> create()
    {
        // ... didn't define concrete_factory but shouldn't matter
        // this just illustrates intent
        return concrete_factoryA->make_object();
    }

    shared_ptr<B> create()
    {
        // ... didn't define concrete_factory but shouldn't matter
        // this just illustrates intent
        return concrete_factoryB->make_object();
    }
};

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?

Aucun commentaire:

Enregistrer un commentaire