在Delphi中绕过循环引用

Tom*_*Tom 15 delphi circular-reference

有没有办法在Delphi中绕过循环单元引用?

也许是更新版本的delphi或某些魔法黑客或其他东西?

我的delphi项目有10万多行代码,主要基于单例类.我需要重构这个,但这意味着几个月的"循环引用"地狱:)

Rob*_*ank 43

在过去的10年里,我一直在维护近百万行遗留代码,所以我理解你的痛苦!

在我维护的代码中,当我遇到循环使用时,我经常发现它们是由单元A中单元A所需的常量或类型定义引起的.(有时它也是一小部分代码(甚至是单元A中的全局变量,单元B也需要.

在这种情况下(当我很幸运的时候!)我可以仔细地将代码的这些部分提取到一个包含常量,类型定义和共享代码的新单元C. 然后单元A和B使用单元C.

我发布了上面的一些犹豫,因为我不是软件设计方面的专家,并且意识到这里有许多其他人比我更有知识.但是,希望我的经验会对你有所帮助.

  • +1.恕我直言,这里不需要犹豫. (6认同)

da-*_*oft 14

  1. 看来,你有相当严重的代码设计问题.除了这些问题的许多迹象,一个是单位循环参考.但正如你所说 - 你无法重构所有代码.
  2. 将所有可能的内容移至"实施"部分.他们被允许有循环引用.
  3. 要简化任务(2),您可以使用3d party工具.我建议 - Peganza Pascal Analyzer(http://www.peganza.com).它将建议您可以移动到实现部分.为您提供更多提示,以提高您的代码质量.

  • 我不赞同第一点.在将一个单元重构为多个单元中可能出现的循环引用并不总是初始代码设计不良的证据.它们是编译器限制的结果,而不是"好"或"坏"代码.示例:使用Delphi 2009 Enterprise为GoF访客模式创建代码,所有代码都包含在一个单元中 - 如果我尝试将其拆分为模型和访问者类的单元,我会遇到循环引用.访问者模式中是否存在代码设计问题?(见http://stackoverflow.com/questions/2356318/) (3认同)

Ken*_*ite 9

使用实现部分使用只要有可能,并限制有什么在接口使用子句什么都有是在接口声明可见.

没有"神奇的黑客".循环引用会导致编译器无限循环(单元A需要编译单元B,这需要编译单元A,这需要编译单元B等).

如果您有一个特定的实例,您认为无法避免循环引用,请编辑您的帖子并提供代码; 我相信这里有人可以帮助你弄清楚如何修复它.

  • 不,他们不会.例如,C程序通常对循环依赖性没有任何问题.编译器编译模块A,发现模块B未编译,只需分析B的源代码编译A然后编译B. (2认同)

Ken*_*ssa 7

有许多方法可以避免循环引用.

  1. 代表们.通常,对象将执行一些应该在事件中完成的代码,而不是由对象本身完成.无论是因为项目工程师的工作时间太短(不是我们总是?),没有足够的经验/知识或者只是懒惰,这样的代码最终会在应用程序中出现.真实世界的例子:TCPSocket组件直接更新应用程序的MainForm上的一些可视组件,而不是让主窗体在组件上注册"OnTCPActivity"过程.

  2. 抽象类/接口.使用其中任何一个都可以消除许多单元之间的直接依赖关系.抽象类或接口可以在其自己的单元中单独声明,从而将依赖性限制为最大值.例子:我们的应用程序有一个调试表单.它几乎用于整个应用程序,因为它显示来自应用程序各个区域的信息.更糟糕的是,每个允许显示调试表单的表单也最终都需要调试表单中的所有单元.更好的方法是使用一个基本上为空的调试表单,但它具有注册"DebugFrames"的能力.

    TDebugFrm.RegisterDebugFrame(Frame:TDebugFrame);

    这样,TDebugFrm没有自己的依赖性(除了在TDebugFrame类上).需要显示调试表单的任何和所有单元都可以这样做,而不会冒太多依赖性添加的风险.

还有很多其他例子...我打赌它可以填补自己的一本书.以时间有效的方式设计干净的类层次结构非常困难,并且它具有经验.了解可用于实现它的工具以及如何使用它是实现它的第一步.但要回答你的问题......对你的问题没有一个尺寸适合所有答案,它总是根据具体情况进行.