是圆形类依赖从一个编码风格点不好?
例:
在数据库应用程序,我们有两个班,约一个单一的数据库(一个封装信息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);
}
}
我的同事认为,这是不好的做法,如果有没有圆形的像这里的依赖只有一个方向是可能会更好。
这是不好的做法,反模式或代码味道? 有什么缺点?
在一般情况下,我会叫循环依赖一个代码味道。 注意,术语“代码味道”主要指“这里是一段代码,需要特别注意,并有可能从重新设计中获益。”
在大多数情况下,我会认真考虑一个设计,其中一个循环依赖是没有必要的,但在少数情况下,可能会好起来。
在您的例子中,ConnFactory似乎是多余的,但可能是因为你的榜样已经下调。 在我看来,不过,连接创建逻辑会更好,如果它被转移到了DBINFO类。 当你已经有一个包含有关数据库数据的类,它似乎只是自然让它负责创建该数据库的连接。
是的,一般来说循环依赖是不好的,但并不总是坏事。 与循环依赖的问题包括紧密耦合,相互依存的模块和一般多米诺效应,当一个模块中的变化传播到其他模块。
在这就是说,你的代码违反单一职责原则DBInfo
不但存储有关数据库的信息,而且还负责获取Connection
对象。 删除的功能,特别是一块独立的阶级,一切都会好起来。
不必要
我不认为在类粒度级别的循环依赖是不好的。 我没有看到一个问题,如果两个,三个或者是四个类是相互依存的。 (我不是说这是你想要的东西,但它可以在某些情况下确定)。
这是一个问题,如果你有在封装或模块级的相互依存,上面和下面提及的所有原因。
此代码仅适用ConnFactory.getConnection()
是静态的。 更好的解决方案是使getConnection()
的实例方法ConnFactory
。 然后你DBINFO可以采取ConnFactory
作为参数(可能是在构造函数中,如果你有一个重载的构造函数)。 但是,我认为这种情况下,可以使用静态方法的更多的是一种不好的做法比圆形参考。
如果你走这条路线,不过,我也将成为一个接口IConnFactory
是DBInfo
将与和互动ConnFactory
将实施。 则没有循环引用-既DBInfo
和ConnFactory
将取决于IConnFactory
,这将取决于两者都不是。
我所知道的是,循环依赖会变得有点问题,当你开始使用依赖注入框架如构造图。 大多数这些框架有麻烦处理循环依赖,有时会导致堆栈溢出异常(原谅双关语:-))。因此我倾向于尽量避开它,除非绝对必要的,无法避免。
怎么样的双向一个一对多关系,即是在使用ORM层的任何应用这种常见的情况? 这难道不是一个循环依赖的情况?
它是坏/代码味道?
循环依赖是不好的,因为:
- 两个依赖超过一个
- 你无法增量测试(不嘲笑他们中的一个,这将是傻小,紧密耦合的东西)。
你可以做所有的东西与接口如果需要打破循环依赖,但简单的最小的解决方案是只是让DBINFO嵌套类ConnFactory的。 引用本身的单位不是圆形的。