Если я правильно понял, то этот вопрос касается рефакторинга класса ConcreteObject
.
Подход № 1:
Если вы можете сделать performBehavior()
часть базового класса BehaviorAbstract
, тогда вы можете просто использовать вектор BehaviorAbstract*
и позволить полиморфизму делать свое дело.Я думаю, что это можно рассматривать как шаблон стратегии.
#include <iostream>
#include <vector>
typedef int Info;
struct BehaviorAbstract
{
virtual void processInfo(Info i) = 0;
virtual void performBehavior() = 0;
};
struct Behavior1 : BehaviorAbstract
{
void processInfo(Info i) override
{ std::cout<< "Behavior1::processInfo()" <<std::endl; }
void performBehavior() override
{ std::cout<< "Behavior1::performBehavior()" <<std::endl; }
};
struct Behavior2 : BehaviorAbstract
{
void processInfo(Info i) override
{ std::cout<< "Behavior2::processInfo()" <<std::endl; }
void performBehavior() override
{ std::cout<< "Behavior2::performBehavior()" <<std::endl; }
};
//------------------------------------------------//
struct ConcreteObject
{
typedef std::vector<BehaviorAbstract*> vec_behavior;
vec_behavior vba;
ConcreteObject(vec_behavior &&v) : vba(v)
{;}
void processInfo(Info i)
{
for (auto &&itr : vba)
itr->processInfo(i);
}
void perform()
{
for (auto &&itr : vba)
itr->performBehavior();
}
};
int main()
{
ConcreteObject foo = {{new Behavior1(), new Behavior2()}};
foo.processInfo(23);
foo.perform();
}
Пример: https://rextester.com/UXR42210
Подход № 2:
Использование вариадического алгоритмаШаблон, который создает кортеж.Выполните итерацию по этому кортежу и запустите функции.Опять же, если performBehavior1()
и performBehavior2()
могут использовать одно и то же имя функции, тогда это станет проще.Дополнительная сложность заключается в том, что вам нужно написать ручной способ итерации по этому кортежу.Для простоты я вызвал processInfo()
непосредственно из структуры iterate_tuple
.
#include <iostream>
#include <tuple>
typedef int Info;
struct BehaviorAbstract
{
virtual void processInfo(Info i) = 0;
};
struct Behavior1 : BehaviorAbstract
{
void processInfo(Info i) override
{ std::cout<< "Behavior1::processInfo()" <<std::endl; }
void performBehavior1()
{ std::cout<< "Behavior1::performBehavior1()" <<std::endl; }
};
struct Behavior2 : BehaviorAbstract
{
void processInfo(Info i) override
{ std::cout<< "Behavior2::processInfo()" <<std::endl; }
void performBehavior2()
{ std::cout<< "Behavior2::performBehavior2()" <<std::endl; }
};
//------------------------------------------------//
template<typename T, std::size_t N>
struct iterate_tuple
{
static void run(T &t, Info i)
{
std::get<N>(t).processInfo(i);
iterate_tuple<T, N-1>::run(t,i);
}
};
template<typename T>
struct iterate_tuple<T, 0>
{
static void run(T &t, Info i)
{
std::get<0>(t).processInfo(i);
}
};
//------------------------------------------------//
template<typename ...T>
struct ConcreteObject
{
std::tuple<T ...> tmp;
static constexpr std::size_t tuple_size = std::tuple_size<decltype(tmp)>::value;
ConcreteObject() : tmp{std::forward<T>(T()) ...}
{;}
void processInfo(Info i)
{
iterate_tuple<decltype(tmp), tuple_size-1>::run(tmp, i);
}
void perform()
{
std::get<0>(tmp).performBehavior1();
std::get<1>(tmp).performBehavior2();
}
};
int main()
{
ConcreteObject<Behavior1,Behavior2> foo;
foo.processInfo(23);
foo.perform();
}
Пример: https://rextester.com/SBRE16218
Оба подхода позволяют избежать множественного наследования, что, как я понял,чего ты хочешь избежать.К вашему сведению, чем проще, тем лучше.