我试图了解基于策略的设计使用模板的真正要求。通过C ++中新的模板化设计,我发现基于策略的类设计是一种高度建议的设计方式,允许您“插入”来自策略类的不同行为。一个最小的例子是以下(维基的缩短版本):
template <typename LanguagePolicy>
class HelloWorld : private LanguagePolicy
{
using LanguagePolicy::message;
public:
// Behaviour method
void run() const
{
// policy methods
cout << message();
}
};
class LanguagePolicyA
{
protected:
std::string message() const
{
return "Hello, World!";
}
};
//usage
HelloWorld<LanguagePolicyA> hello_worlda;
hello_worlda.run(); // prints "Hello, World!"
快速分析表明,为了获得不同的可插入方法message()
,我们继承了模板化类型,其定义可由任何人提供(并在编译时识别)。
但是,不使用模板化代码和简单的旧学校运行时多态,可以实现相同级别的抽象(和可配置方法),如下所示。
class HelloWorld
{
LanguagePolicy *lp; //list of all plugable class
public:
HelloWorld(LanguagePolicy *lpn) {
lp = lpn;
}
// Behaviour method
void run() const
{
// policy methods
cout << lp->message();
}
};
class LanguagePolicy
{
protected:
virtual std::string message() const;
};
class LanguagePolicyA: LanguagePolicy
{
protected:
std::string message() const
{
return "Hello, World!";
}
};
//usage
HelloWorld helloworld(new LanguagePolicyA);
helloworld.run();
功能性和抽象级别我没有看到两种方法有太大差异(即使第二种方法对LanguagePolicy
几乎没有额外的代码行,我认为其他用户需要它了解界面;否则理解LanguagePolicy
取决于文档)。但我确实认为后者是“干净的”(来自未使用模板的人)。这是因为在我看来,非模板化的课程看起来和理解都比较清晰。一个非常好的例子是流行的库VTK(可视化工具包),它使用第二种方法解决了许多不同的问题。即使没有关于VTK的大量文档,我们大多数人 - 它的用户,只能看看它的类图(有时候它们很大)并推断出类的行为;并在我们的应用程序中开发高度可配置和复杂的管道(无法将VTK映像为基于模板:))。相反的是像STL / BOOST这样的库,我认为任何人都无法在不使用大量文档的情况下识别类的工作。
所以我的问题是,基于模板的策略设计是否真的优于(仅在基于策略的设计的场景中)而不是基于虚拟继承?如果是的话,何时以及为何?
答案 0 :(得分:1)
两者都是有效的结构化方式,实际上取决于要求。 E.g。
运行时与编译时多态性。
你想什么/能/必须实现多态?
虚拟来电的性能开销
模板生成没有间接的代码
该课程的实际用法。
当你必须存储异构集合时,需要一个基类,所以你必须使用继承。
关于基于政策的设计的一本非常好的书(有点过时但很好)Modern C++ Design
答案 1 :(得分:1)
取决于我猜的情况......使用模板的一个可能的缺点是该类型应该在编译时知道:
HelloWorld<English> hw; // English is plugged at compile-time
在你的第二个例子中,你使用指向基类的指针,这个指针可能指向各种派生类。它指向的内容不需要在编译时知道,因此可以在运行时通过(用户)输入确定。这种方法的一个可能的缺点是虚拟呼叫开销。在某些应用程序中,以及在某些平台上,这可能是不受欢迎的。