C++:基类调用自己的虚函数——一种反模式?

标签 c++ oop design-patterns c++14

我看到像下面这样的模式很常用。我们有一个基类完成大部分工作,但调用它自己的虚拟/纯虚拟函数之一来完成每个派生类型不同的部分工作。一个人为的例子:

struct PacketProcessor {
    virtual void parseEncap(pkt) = 0;
    void process(Pkt pkt)
    {
        parseEncap(pkt);  // Calls its own virtual function to parse the encap
        processFurther(pkt);
        ...
    }
};

我们创建派生类来覆盖虚函数并提供特定于派生类的功能。

struct EthernetProcessor : public PacketProcessor {
    void parseEncap(Pkt) override { // parse ethernet encap}
};

struct PPPProcessor : public PacketProcessor {
     void parseEncap(Pkt) override { //parse ppp encap }
};

但我觉得这种模式,随着时间的推移,越来越多的基类中的函数被虚拟化,或者在随机的地方添加和调用更多的虚函数,为不同的派生类行为腾出空间。

[在现实生活中我看到了 add() 和 add_extra() 虚函数:-)]

随着时间的推移,代码不再具有固定的结构,因为每种类型都以完全不同的方式处理。即使公共(public)基类在某种程度上给出了错误的概念结构。但是,是的,它仍然保持不同类型的代码隔离,而不是 if (type1)/else(type2)。

另一种实现类似方法的方法是将差异抽象到不同的类(层次结构)中并调用其中的虚函数。这也很常见例如:

struct Encap {
    virtual void parseEncap(Pkt) = 0;
};

struct EthernetEncap : public Encap {
    void parseEncap(Pkt pkt) {}
};

struct PPPEncap : public Encap {
    void parseEncap(Pkt pkt) {}
};

struct PacketProcessor {
    PacketProcessor(Encap *encap) : m_encap{encap} {}
    void process(Pkt pkt)
    {
       m_encap->parseEncap(pkt);
       processFurther(pkt);
       ...
    }
private:
    EncapPtr m_encap;
};

但在这种情况下,也可以在 Encap 类中添加一些无聊的功能。或者会有太多的组件类,比如提供不同功能的 Encap。

但好处是 PacketProcessor 将遵循所有类型的 Encaps 的特定路径。此外,这种方法不如前一种模式灵活,因为我们需要将所有“封装”放入一个非常具体的模型中。

所以我的问题是:

其中之一是反模式并且应该避免还是缺点只是缺乏纪律并且与遵循的模式无关。

最佳答案

该模式称为 template method pattern .

But I feel with this sort of pattern, as time goes on, more and more functions in the base class gets virtualized or more virtual function added and called at random places to make room for different derived class behavior.

该模式通常应用在框架内,其中基类由框架提供,然后实际功能由框架的用户提供。在这种情况下,基类相当稳定,而用户数量和实现的可变性很大。在那种情况下,该模式做得很好。

您的情况似乎有点不同,因为我知道您可以控制基类和实现。如果这是真的,那么模板方法模式可能不是您真正需要的。

Is either one of these an anti-pattern and should avoided or drawbacks simply lack of discipline and nothing to do with the pattern followed.

老实说,我并不完全理解您的替代方法。但是,我看不到它有任何根本性的损坏。但是,考虑到如果基类和派生类不在您的控制之下,您的方法与模板方法方法有很大不同。

任何模式都可能被误用和过度使用。此外,没有任何模式是没有选择的。模式的主要好处无非就是它们是模式。他们可以被认出来。您的第一个片段已被多个用户识别为模板方法模式,而第二个片段实际上没有冒犯,只是另一个类层次结构。

TL;DR 模式不是 chalice 。仅仅因为一种模式可能被滥用并不意味着该模式已被破坏。如果您认为变体或完全不同的东西更适合您,那就继续吧。

关于C++:基类调用自己的虚函数——一种反模式?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57316960/

相关文章:

c++ - C++ 中的动态 QT4 菜单

c++ - 在堆栈上分配不完整类型

java - 在需要接口(interface)时传递特定对象的列表。如何?

java - 类型安全的异构容器模式来存储项目列表

java - 如何在 UML 类图中创建用户/角色关系?

c++ - 二叉搜索树 - 按两个数据项排序

php - 在 MVC 中处理片段和 View

PHP 面向对象 : How to get database rows as objects?

java - 对象转换模式

构造函数中的 JavaScript 访问器属性