我参与过一些这样的系统。有许多不同的做事方式。但我过去做过的一种常见方法是让 Node 对象链接到其他 Node 对象。节点通过一些 IAction 接口包含一个动作对象。用户以某种方式指定在特定节点处实现 IAction 接口的具体动作对象(这通常还涉及为对象指定一些状态,例如要应用的过滤器的参数)。
然后有一个框架来初始化(编译)和执行(运行)图,并安排在输入准备好时调用 IAction 接口并将输入传递给节点,并将输出传递给下游节点。这是一个非常简单的算法:并行运行所有输入都存在的节点(从没有输入的节点开始),然后将其余节点放在等待队列中,直到它们的输入存在。
这只是如何做到这一点的一种方式;正如您所指出的,有许多变体,以及许多使用这种技术的系统。也有一些框架(如果我理解正确的话, TPL Dataflow就是其中之一)。
关于如何确保节点之间的连接保持一致的问题,在我看来,这归结为在框架做多少和节点做多少之间做出选择。在一个极端,框架可以在图“编译时”严格匹配连接类型;另一方面,框架可以将其留给节点在“运行时”进行检查。如果大多数连接只是相同的类型,例如它们都是字节流,则后者可能是合适的。
顺便说一句,在 Java 或 C#(或其他 HLL)中可能比在 C++ 中更容易,因为对接口、反射、动态加载对象等有更多支持(例如,在 C# 中,您可以轻松地为对象指定类型和从流中动态创建它,而您必须自己在 C++ 中滚动)。