Java包之间的每个循环引用都是坏的吗?

时间:2013-05-14 05:03:44

标签: java reference sonarqube cyclic

我一直在使用Sonar代码质量管理平台,并且在大多数情况下,我发现它在揭示我的代码库的隐藏设计缺陷方面非常有用。

然而,有一条规则给了我更多的烦恼而不是帮助,这是对“循环包参考”违规的检查。

我想我完全明白pacakges之间的这种依赖性是一件坏事。例如,在典型的3层表示/服务/持久性分层设计中,让数据库处理代码具有对UI相关类的引用几乎总是一个坏主意。将它称为“违规”我没有问题。

但是让我们考虑其他情况,即像设计像应用程序一样的IDE。比如说,我们有一个包含 Application 接口的主程序包,它定义 List Application.getViews()方法来引用应用程序的视图。

但是,当 View 接口有 Application getApplication()方法引用回其父应用程序时,我认为这是一个非常常见的设计,它将介绍循环引用,前提是每个接口分别在 com.myapp.ui com.myapp.ui.view 中分开。

当然,您只需将 View 界面放入 com.myapp.ui 即可打破循环。但是当您在 com.myapp.ui.view 中有各种其他视图相关的APIS时,其中许多是另一个抽象API,如 AbstractView ContentView AbstractContentView 等,我想知道为了管理目的将它们保存在单独的包中是否更明智。

并且考虑到所述应用程序还有许多其他类似的情况,例如 com.myapp.ui.action com.myapp.ui.perspective 等,这些都会使 com.myapp.ui 如果我们要把它们全部放在那里,那就太拥挤了。

那么,您建议采用什么方法来应对这种情况?真的每个循环包都引用了一件坏事吗?或者如果我不得不忍受它们,你如何配置Sonar只检查真实的,有问题的循环?

谢谢!

2 个答案:

答案 0 :(得分:6)

每一个绝对 - 除了这个;) - 在某些时候会出错。那么,每个循环参考都不好吗?不,你必须使用你的判断。

但是如果你确实引入了循环依赖,那么值得问你是否真的需要它,以及为什么。 tl; dr经常是这样,你可能会发现打破循环可以提高你的模块性,特别是你能够单独测试组件。

要使用您的示例,视图是否真的需要getApplication(),这可能会返回一个相对“重”的对象(即,一个本身需要数据库,网络等等)? 也许 ......但也许不是。如果您真正需要的getApplication是一些带有一些回调的东西(例如当用户启动某些操作时),那么在该回调的某个公共包中创建一个接口可能会很有用。所以,而不是:

com.foo.app.Application
com.foo.view.View
    Application getApplication()

你有:

com.foo.common.Callback // maybe just a Callable, Runnable, etc?
com.foo.app.Application
    provides a Callback for some action foo
com.foo.view.View
    Callback getFooCallback()

你应该问的问题是:这给了我什么?这可能是你必须非常存在,以至于它不会给你太多 - 尽管这可能暗示你可以将你的课分开一些。但实际上它可能会更容易测试你的视图,因为现在你的单元测试可以(1)测试视图而不需要启动整个应用程序,并且(b)提供一个“虚拟”回调,它可以像保存一样描述该操作的字符串,然后您的单元测试断言它保存了正确的字符串。

答案 1 :(得分:0)

确实有一张开放的JIRA票,以防止将父/子套餐之间的循环视为质量缺陷:http://jira.codehaus.org/browse/SONAR-3452