1

我有一个 DLL,比如 A,它实现了求解数学方程的通用算法。我有另一个 DLL,比如说 B,它实现了数学方程 DLL B 使用 DLL A 来求解它的方程,但 DLL B 必须能够从 DLL A 执行给定的方程(DLL A 实现了一些数值、邻近方法和“尝试”给定方程上的不同值作为其走向所需数学解的步骤)现在,DLL A 必须“知道” DLL B,反之亦然。

这是一个“坏”的设计吗?我可以考虑像业余cos这样的代码吗?你会怎么做(请记住 DLL A 实现了由实现数学方程的不同其他 DLL 使用的通用算法)?

谢谢大卫

4

5 回答 5

1

这个问题(包之间实现的循环依赖)正是创建依赖倒置原则(DIP)的原因。Charles Bailey 提供了一个使用 DIP 来打破依赖的解决方案。与其将两个具体的类(类或函数,应用 DIP 没有太大区别)直接相互耦合,不如将它们耦合到一个抽象。

在这种情况下,我们有一个定义“数学函数”并由求解器 DLL 使用的接口。我们还有一个定义“求解器算法”的接口,由函数 DLL 使用。我们有具体的类/函数取决于抽象。在 C++ 术语中,这些将是接口,当调用函数 DLL 中的方法时,求解器会将自身作为指向“求解器接口”的指针传递给函数。该函数调用求解器接口上的方法以在适当的点回调求解器。类似地,求解器有一个类,它接受一个指向数学函数接口的指针,并在适当的时间回调函数。

Bob Martin 的书《C# 中的敏捷原则、模式和实践》涵盖了这些面向对象的设计原则,包括 DIP。他有具体的例子在实践中展示了这些原则。尽管本书使用 C#(第一版使用 Java),但同样的原则和实践也适用于 C++。

于 2009-07-20T03:43:35.880 回答
1

没有理由 DLL A 需要明确了解 DLL B,它只需要一个接口来能够评估它已被解决的方程。

接口可以由函数签名指定,指向合适函数的指针将由 B 传递给 A,或者它可以呈现为抽象类,并且可以将指向实际派生实例的指针或引用从 B 传递给一个。

尽管有可能拥有相互依赖的 dll,但通常不是一个好主意。在这种情况下,我认为没有必要。

于 2009-07-19T20:36:51.987 回答
1

似乎 A 是一个较旧的 dll,因为它被许多其他人使用。看起来很糟糕的是您需要更改 A 以便它显式调用 B,这可能表明您将在 A 中一次又一次地进行更改。这是个坏消息,因为更改 A 将需要重建所有其他 dll。

您需要通过引入您提供给 B 的任何形式的回调(虚拟、回调、模板)来抽象 B 如何执行方程式或 A 如何求解方程式。我会选择 B,因为 A 较旧且可能更常用。这是一些伪代码,其中 Solver 是 A 类, Equation 是 B 类:

solver=new Solver;
equation=new Equation(&solver);

Solver 需要实现某种抽象接口。最佳解决方案取决于您的语言和框架。谷歌“依赖倒置原则”或“依赖注入”。

于 2009-07-19T21:05:28.590 回答
0

如果您正在实现一个回调模式,其中 DLL A 发布一个回调接口,而 DLL B 根据该接口实现回调方法并在调用 A 时提供一个指向它的指针,那么这不是一个糟糕的设计。

  • 长时间运行的函数的进度回调是这种模式的常见用法。
  • 像求解器这样的协同程序,带有回调注入候选算法(可能匹配另一个接口)是另一个常见的例子。
于 2009-07-20T03:45:18.170 回答
0

这是个好问题。是的,那将是一个糟糕的设计。两种解决方案:

  • 将所有内容放在同一个 DLL 中
  • 将 A 拆分为两个 DLL(一部分由 B 使用,另一部分由 B 使用)

您可以通过谷歌搜索“循环”和/或“非循环”“依赖”来找到有关此主题的更多信息。

于 2009-07-19T20:37:47.100 回答