I have a bunch of algorithms and collections, and I am using a Policy Based design (see the book Modern C++ Design) to deal with arbitrary combinatorial complexity. This is great, but in order to prevent the destruction of the Host class by using the pointer to a policy, 1 suggests to make the destructors of policied protected. However, if I make the Algorithm and Collection destructors protected, I cannot use them on their own, but only as policies. Also, I don't see the benefits of the Policy Based design, compared to a Generic Factory Pattern...
Here is the model of the code:
#include <iostream>
template<class Collection>
class AlgorithmOne
{
public:
void doSomethingWithData(Collection& data)
{
// Use Collection iterators to build up an algorithm.
}
};
template<class Collection>
class AlgorithmTwo
{
public:
void doSomethingWithData(Collection& data)
{
// Use Collection iterators to build up an algorithm.
}
};
template<class Collection>
class AlgorithmThree
{
public:
void doSomethingWithData(Collection& data)
{
// Use Collection iterators to build up an algorithm.
}
};
template<class Element>
class CollectionOne
{
public:
typedef Element ElementType;
};
template<class Element>
class CollectionTwo
{
public:
typedef Element ElementType;
};
template<class Element>
class CollectionThree
{
public:
typedef Element ElementType;
};
template<typename HostTraits>
class HostInheritsData
:
public HostTraits::Collection,
public HostTraits::Algorithm
{
public:
typedef HostTraits Traits;
using Traits::Algorithm::doSomethingWithData;
void doSomethingWithData()
{
doSomethingWithData(*this);
}
};
template<typename HostTraits>
class HostCompositsData
:
public HostTraits::Algorithm
{
typename HostTraits::Collection data_;
public:
typedef HostTraits Traits;
using Traits::Algorithm::doSomethingWithData;
void doSomethingWithData()
{
doSomethingWithData(data_);
}
// Clumsy and breaking encapsulation
typename HostTraits::Collection& data()
{
return data_;
}
};
template<typename HostTraits>
class GenericStrategy
{
typename HostTraits::Collection data_;
typename HostTraits::Algorithm algorithm_;
public:
void doSomethingWithData()
{
algorithm_.doSomethingWithData(data_);
}
};
class ElementOne {};
class ElementTwo {};
class ElementThree {};
struct MyConfig
{
typedef ElementOne Element;
typedef CollectionThree<Element> Collection;
typedef AlgorithmOne<Collection> Algorithm;
};
int main(int argc, const char *argv[])
{
HostInheritsData<MyConfig> hostInherits;
hostInherits.doSomethingWithData();
// This must be a mistake, are policies meant to be used this way?
hostInherits.doSomethingWithData(hostInherits);
HostCompositsData<MyConfig> hostComposits;
hostComposits.doSomethingWithData();
// Clumsy to use, not intuitive and breaking encapsulation.
hostComposits.doSomethingWithData(hostComposits.data());
// Combinatorics are there, I can combine whatever I want in MyConfig as for
// policies, but I can also have global Algorithm and Collection objects
// (no protected destructors).
GenericStrategy<MyConfig> strategy;
strategy.doSomethingWithData();
return 0;
}
Here are my questions:
I am customizing the structure of a Host class using policies, how can I trully enrich the interface of the Host class, when every realistic Algorithm requires a Collection to work on, and the Collection is encapsulated in the host?
When I compare the Policy Based Design together with a Generic Factory, doesn't the Generic Factory bring me the same combinatorial complexity? It seems that using the Generic Factory is better since I can interchange Element, Container and Algorithm in all possible combinations as well, and I can still have public destructors for all the Policies, which allows me to combine them in any way I want, e.g. a global combination of Element, Collection and Algorithm.
It seems to me that the Enriched Policies become a problem as soon as the structure is customized. Even if I later on add a member function to an algorithm, it will probably have parameters related to Collection (e.g. Collection iterators): if the Host encapsulates Collection using composition, I need to ask it for the parameter of its own member function:
// Clumsy to use, not intuitive and breaking encapsulation.
hostComposits.doSomethingWithData(hostComposits.data());
and if the Host encapsulates the Collection using inheritance, it gets (to me at least) even weirder:
// This must be a mistake, are policies meant to be used this way?
hostInherits.doSomethingWithData(hostInherits);
Did I completely misunderstand Policy Based design (yet again), am I using the traits properly?
Is the Generic Strategy Pattern a better choice in this case?