2

我的团队编写了几个通过纯虚拟回调实现事件处理的 C++ 类——例如,当从另一个进程接收到消息时,处理 IPC 消息传递的基类调用它自己的纯虚函数,派生类处理事件覆盖该功能。基类知道事件已经发生;派生类知道如何处理它。

我现在想将这些基类提供的功能组合到更高级别的类中,例如,当消息从另一个进程到达时,我的新类可以使用类似的事件驱动网络类通过其网络连接转发它. 看起来我有两个选择:

  • (1) 组合:从每个事件处理基类派生类,并将这些派生类的对象作为成员添加到我的新类中,或者:

  • (2) 多重继承:使我的新类成为所有事件处理基类的派生类。

我已经尝试过(1)和(2),但我对我的实现都不满意。

还有一个额外的复杂性:一些基类是使用初始化和关闭方法而不是使用构造函数和析构函数编写的,当然这些方法在每个类中具有相同的名称。所以多重继承会导致函数名不明确。可以通过using声明和/或显式范围解决,但不是我见过的最易于维护的东西。

即使没有这个问题,使用多重继承并覆盖几个基类中的每一个的每个纯虚函数都会使我的新类变得非常大,接近“上帝对象”。随着需求的变化(阅读:“随着需求的增加”),这不会很好地扩展。

另一方面,使用单独的派生类并将它们添加为我的新类的成员意味着我必须在每个派生类上编写大量方法以在它们之间交换信息。这感觉很像“getter and setter”——没有那么糟糕,但是有很多“从那个类中获取这些信息并将其交给这个类”,这给人一种效率低下的感觉——很多额外的方法,很多额外的读取和写入,并且类必须对彼此的逻辑了解很多,这感觉不对。我认为一个成熟的发布和订阅模型将是矫枉过正,但我​​还没有找到一个简单的替代方案。

如果我使用组合,也会有很多重复的数据。例如,如果我的班级的状态取决于其网络连接是否已启动并正在运行,那么我必须在受此影响的每个班级中都有一个状态标志,或者让每个班级在每次需要做出决定时都向网络班级查询其状态做出来。如果我只有一个多重继承类,我可以只使用我类中的任何代码都可以访问的标志。

那么,多重继承、组合,或者完全是别的什么?是否有关于如何最好地处理这种事情的一般经验法则?

4

2 回答 2

1

根据您的描述,我认为您已经采用了“模板方法”样式的方法,其中基础确实可以工作,然后调用派生类实现的纯虚拟,而不是几乎相同的“回调接口”方法,除了纯虚方法位于一个完全独立的接口上,该接口作为构造函数的参数传递给“基”。我个人更喜欢后者,因为当需要将对象连接在一起并构建更高级别的对象时,我发现它更加灵活。

我倾向于使用实现组合对象所需的回调接口的组合类进行组合,然后可能在更高级别以类似的风格再次组合。

然后,您可以通过让组合对象实现回调接口并将它们传递给其构造函数中的“组合”对象来决定组合是否合适,或者您可以在其自己的对象中实现回调接口,可能使用更简单和更精确的回调您的组合对象实现的接口,并组合“基础对象”和“回调实现对象”......

就我个人而言,我不会使用“抽象事件处理”接口,因为我更喜欢我的代码明确和清晰,即使这会导致它稍微不那么通用。

于 2012-09-06T12:12:48.003 回答
0

我并不完全清楚你的新类试图实现什么,但听起来你实际上必须在某个地方为所有这些抽象事件类提供一个新的实现。

就个人而言,我会为作曲而丰满。多重继承很快就变成了一场噩梦,特别是当事情必须改变时,组合保持现有的关注点分离。

您声明每个派生对象都必须与网络类进行通信,但是您可以尝试将其减少到最低限度。例如,每个派生事件对象纯粹负责将事件信息打包成某种通用数据包,然后将该数据包传递给网络类进行发送?

如果不确切知道你的新类在做什么,很难评论或建议更好的模式,但是我编码的越多,我就越学会同意古老的格言“喜欢组合而不是继承”

于 2012-09-06T09:07:43.830 回答