从编码风格的角度看,循环类依赖是不是很糟糕?
示例:
在数据库应用程序中,我们有两个类,一个封装有关单个数据库(DBInfo
)的信息,另一个类可以创建数据库连接。 (ConnFactory
)
DBInfo
有getConnection
方法,使用ConnFactory
创建连接。但ConnFactory
本身需要DBInfo
个对象才能这样做。
像这样:(为了便于阅读,忽略了任何编码风格)
class DBInfo {
String name;
String connectionUrl;
Connection getConnection() {
return ConnFactory.getConnection(this);
}
}
class ConnFactory {
Connection getConnection(DBInfo toWhat) {
return new Connection(toWhat.connectionUrl);
}
}
我的同事认为这是不好的做法,如果只有一个依赖方向而没有像这里那样的循环方向会更好。
这是一种不好的做法,反模式还是代码味道?有什么缺点吗?
答案 0 :(得分:15)
一般来说,我会将循环依赖称为Code Smell。请注意,术语“代码嗅觉”主要表示“这里是一段需要特别注意的代码,并且可能会从重新设计中受益。”
在大多数情况下,我会强烈考虑一种不需要循环依赖的设计,但在极少数情况下可能没问题。
在您的示例中,ConnFactory似乎是多余的,但这可能是因为您的示例已被削减。但是,在我看来,如果它被移动到DBInfo类,那么Connection创建逻辑会更好。如果您已经有一个包含数据库数据的类,那么让它负责创建与该数据库的连接似乎很自然。
答案 1 :(得分:8)
是的,一般来说,循环依赖是坏的,虽然并不总是邪恶的。当一个模块中的更改传播到其他模块时,循环依赖的问题包括紧耦合,相互依赖的模块以及通常的多米诺效应。
尽管如此,您的代码违反了单一责任原则,因为DBInfo
不仅存储有关数据库的信息,还负责获取Connection
个对象。将该特定功能删除到单独的类中,一切都会好的。
答案 2 :(得分:7)
不一定
我不认为类粒度级别的循环依赖性不好。如果两个,三个或者四个类相互依赖,我没有看到问题。 (我不是说这是你想要的东西,但在某些情况下可以没问题。)
如果您在程序包或模块级别具有相互依赖性, 是一个问题,原因如上所述。
答案 3 :(得分:4)
此代码仅在ConnFactory.getConnection()
为静态时有效。更好的解决方案是使getConnection()
成为ConnFactory
的实例方法。然后你的DBInfo可以使用ConnFactory
作为参数(如果你有一个重载的构造函数,可能在构造函数中)。但是,我认为在这种情况下使用静态方法比循环引用更糟糕。
但是,如果您要走这条路线,我还会创建IConnFactory
与DBInfo
进行互动且ConnFactory
将实施的界面DBInfo
。然后没有循环引用 - ConnFactory
和IConnFactory
都取决于{{1}},这两者都不依赖。
答案 4 :(得分:2)
我所知道的是,当您开始使用结构图等依赖注入框架时,循环依赖可能会成为一个问题。大多数这些框架在处理循环依赖时遇到问题,有时会导致堆栈溢出异常(请原谅双关语:-))因此,除非绝对必要且无法避免,否则我倾向于避免使用它。
答案 5 :(得分:1)
在使用ORM层的任何应用程序中,这种常见情况的双向一对多关系怎么样?这不是循环依赖的情况吗?
这是不好/代码味?
答案 6 :(得分:0)
循环依赖性很糟糕,因为:
如果需要,您可以使用接口完成所有内容以打破循环依赖关系,但直接的最小解决方案是使DBInfo成为ConnFactory的嵌套类。引用自身的单位不是循环的。