什么时候更喜欢模板化的基于策略的设计而非基于非模板化继承的设计

kri*_*s89 7 c++ polymorphism policy inheritance templates

我试图了解基于策略的设计使用模板的真正要求.通过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!"
Run Code Online (Sandbox Code Playgroud)

快速分析表明,为了获得不同的可插入方法,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();
Run Code Online (Sandbox Code Playgroud)

功能性和抽象级别我并没有看到两种方法有太大区别(尽管第二种方法几乎没有额外的代码行LanguagePolicy,我认为其他用户需要知道接口;否则理解LanguagePolicy取决于根据文件).但我确实认为后者是"干净的"(来自未使用模板的人).这是因为在我看来,非模板化的课程看起来和理解都比较清晰.一个非常好的例子是流行的库VTK(可视化工具包),它使用第二种方法解决了许多不同的问题.虽然没有关于VTK的大量文档,但是我们大多数人 - 它的用户,可以只看一下它的类图(有时它们非常大)并推断出类的行为; 并在我们的应用程序中开发高度可配置和复杂的管道(无法将VTK映像为基于模板:)).相反的是像STL/BOOST这样的库,我认为任何人都无法在不使用大量文档的情况下识别类的工作.

所以我的问题是,基于模板的策略设计真的优于(仅在基于策略的设计的场景中)而不是基于虚拟继承吗?如果是的话,何时以及为何?

Tas*_*lou 2

两者都是有效的构建方式,这实际上取决于需求。例如

运行时与编译时多态性。

你什么时候想要/可以/必须实现多态性?

虚拟调用的性能开销

模板生成没有间接寻址的代码

类的实际使用情况。

当你必须存储异构集合时,需要一个基类,所以你必须使用继承。

《Modern C++ Design》是一本关于基于策略的设计的好书(有点过时,但仍然很好)