这是一个关于如何更好处理循环依赖的问题。让我先说一下我认为循环依赖很少是必要的,但代码传给了我,我无法帮助它。
假设对具有概念上相同立场的类存在循环依赖,即没有明显的"拥有"他们之间的关系。我该如何优雅地处理它们?
让我们举个例子来说明我们想要表示房间的可变拓扑,neighbour
是一个反身属性
interface Room {
public void remove(Room r);
}
class Living implements Room {
Room[] neighbour;
public void remove(Room r) {/* implementation */}
}
class Dining implements Room {
Room[] neighbour;
public void remove(Room r) {/* implementation */}
}
现在,显然我们无法在remove
的实现中调用另一个Room
上的remove
,这显然是无休止的递归。但后来我有几个选择:
Room
拥有另一个,以某种方式记录事实,然后只有一种Room
具有remove
能力。removeSelf
,它从不调用另一个Room
的方法,从而解析无限递归。Building
个更高的对象,让它在Room
上执行所有操作它们各自的缺点是
Room
。Building
只是巧合适合成为拥有对象。所以,问题是,如果循环依赖在某种程度上是不可避免的,那么更好的设计是什么?
我们可能会创建一个RoomOperator
类包含在Room
上运行的函数,但它也遇到与上面removeSelf
方法相同的问题:它最终会调用一个方法在RoomOperator
以外非法。
答案 0 :(得分:0)
向房间添加功能,允许他们告诉他们是否需要请求邻居删除它们,从而避免递归。
interface Room {
void remove(Room r);
void removeOther(Room r);
}
class Living implements Room {
List<Room> neighbours;
@Override
public void remove(Room r) {
r.removeOther(this);
neighbours.remove(r);
}
@Override
public void removeOther(Room r) {
neighbours.remove(r);
}
}
方法removeOther(Room r)
告诉房间只从列表中删除提供的房间。这与remove(Room r)
方法形成对比,后者也会导致房间要求提供的房间将其移除。
如果这很重要,这个解决方案可以保持接口方法的完整性。我实际上会让各个房间扩展一个AbstractRoom
类,并在那里添加两个方法的实现。但由于您的两个Room
都是相同的,因此很难知道该怎么做。
如果您可以将方法更改为remove(Room r, boolean callback)
,则可以节省一些混淆并仅使用该方法。
为了便于使用,我还将neighbours
更改为列表。
使用外部管理器(实用程序)类。该课程允许房间无需相互管理。
interface Room {
void remove(Room r);
List<Room> getNeighbours();
}
class Living implements Room {
List<Room> neighbours;
@Override
public void remove(Room r) {
RoomManager.removeRooms(r, this);
}
@Override
public List<Room> getNeighbours() {
return neighbours;
}
}
class RoomManager {
static void removeRooms(Room r1, Room r2) {
r1.getNeighbours().remove(r2);
r2.getNeighbours().remove(r1);
}
}
同样,我在界面中添加了一个方法,以统一房间的构成。抽象类在这里会做得更好。
答案 1 :(得分:0)
您可以添加管理所有依赖项的基类RoomSupport
。其他实现应该扩展RoomSupport
。这里的实现:
abstract class RoomSupport implements Room {
private final Set<Room> neighbours = new HashSet<>();
@Override
public void addNeighbour(Room r) {
if (neighbours.add(r)) {
r.addNeighbour(this);
}
}
@Override
public void remove(Room r) {
if (neighbours.remove(r)) {
r.remove(this);
}
}
}
实现需要注意,添加和删除会终止并且根本没有循环依赖。