【发布时间】:2015-08-16 07:04:19
【问题描述】:
我试图了解使用模板进行基于策略的设计的真正要求。通过 C++ 中的新模板设计,我发现基于策略的类设计是一种强烈建议的设计方式,它允许您从策略类中“插入”不同的行为。一个最小的示例如下(wiki 的缩短版本):
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 这样的库,我认为任何人都不可能在不使用大量文档的情况下识别类的工作。
所以我的问题是,基于模板的策略设计真的比基于虚拟继承的更好吗(仅在这种基于策略的设计场景中)?如果是这样,何时以及为什么?
【问题讨论】:
标签: c++ templates inheritance polymorphism policy