我有一堆算法和集合,我使用的是基于策略的设计(参见书籍Modern C++ Design)来处理任意的组合复杂性。这很好,但是为了防止使用指向策略的指针破坏Host类,1建议使策略的析构函数受到保护。但是,如果我使算法和集合析构函数受到保护,我不能单独使用它们,而只能作为策略使用它们。此外,与通用工厂模式相比,我没有看到基于策略的设计的好处......
以下是代码的模型:
#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;
}
以下是我的问题:
我使用策略自定义Host类的结构,当每个真实的算法需要Collection进行处理,并且Collection被封装在主机中时,我如何能够丰富Host类的接口?
当我将基于策略的设计与通用工厂进行比较时,通用工厂不会给我带来相同的组合复杂性吗?似乎使用Generic Factory更好,因为我可以在所有可能的组合中交换Element,Container和Algorithm,并且我仍然可以为所有策略设置公共析构函数,这允许我以我想要的任何方式组合它们,例如元素,集合和算法的全局组合。
在我看来,只要结构定制,丰富的政策就成了问题。即使我稍后在算法中添加成员函数,它也可能有与Collection相关的参数(例如Collection迭代器):如果Host使用composition封装Collection,我需要询问它自己的成员函数的参数: / p>
// Clumsy to use, not intuitive and breaking encapsulation.
hostComposits.doSomethingWithData(hostComposits.data());
如果主机使用继承封装了Collection,那么它(至少对我来说)甚至更奇怪了:
// This must be a mistake, are policies meant to be used this way?
hostInherits.doSomethingWithData(hostInherits);
我是否完全误解了基于策略的设计(又一次),我是否正确使用了这些特征? 在这种情况下,通用策略模式是更好的选择吗?
答案 0 :(得分:1)
您可能需要仔细考虑设计中耦合的数量。例如。确保您确实希望算法将Collection
作为模板参数。这引入了算法与其操作的容器之间的耦合。看看标准库:它的算法是函数模板,将迭代器作为模板参数。迭代器不知道他们指出的容器(词汇表中的集合)。
为了做除迭代和访问之外的其他事情,算法将稍微更丰富的类型作为参数,例如back_inserters
访问容器的push_back()
成员。但总的来说 - 没有先验知识 - 绝对没有必要将整个容器接口传递给所有算法。要做真正容器特定的事情,将算法嵌入容器成员函数(例如sort()
std::list
成员函数)更合适。
对于稍微不同的事情,有几个相同函数名的重载(例如std::transform
)。只有当你的算法需要维护状态时才真正有必要使它成为一个类模板,最好的方法是使它成为一个函数对象,即包含一个重载的运算符(),而不是DoSomethingWithData()
成员函数。
您的数据参数化方式与标准库相同:以Element
为模板参数的类模板。将此类数据提供给算法的方法是以begin()
和end()
成员函数的形式为您的数据提供迭代器访问。标准容器(vector
,map
,unorderd_map
等)也将策略作为模板参数,例如Allocator
,Compare
或Hash
课程,您可以通过该课程自定义数据的行为。标准智能指针采用Deleter
策略参数来自定义其行为。
简而言之:仔细检查您的设计。你想做什么?每个组件(算法,数据结构)需要了解另一个组件是什么?你能正确使用标准库吗?可以肯定的是,您可能想要的大部分内容已经编码在那里,您可以专注于编写应用程序的逻辑,而不是算法或数据结构细节。