首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >循环依赖设计

循环依赖设计
EN

Stack Overflow用户
提问于 2017-05-15 04:41:02
回答 2查看 856关注 0票数 3

这是一个关于如何更好地处理循环依赖的问题。让我在序言中说,我认为循环依赖很少有必要,但是代码是传给我的,我无法控制。

假设有一个循环依赖于具有概念上平等地位的类(它们之间没有明显的“拥有”关系)。我该如何优雅地处理它们?

让我们举一个例子,我们希望用自反属性neighbour来表示可变的房间拓扑。

代码语言:javascript
复制
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之外是非法的方法。

EN

回答 2

Stack Overflow用户

发布于 2017-05-15 05:39:22

解决方案1

在房间中增加功能,让他们知道是否需要要求邻居移除它们,从而避免了递归。

代码语言:javascript
复制
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更改为列表。

解决方案2

使用外部管理器(实用程序)类。这个类允许不需要房间之间的相互管理。

代码语言:javascript
复制
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);
    }
}

再次,我在界面上添加了一种方法,以统一房间的组成。抽象类在这里会做得更好。

票数 0
EN

Stack Overflow用户

发布于 2017-05-15 05:41:21

您可以添加一个基类RoomSupport,它管理所有的依赖项。其他实现应该扩展RoomSupport。在此,执行:

代码语言:javascript
复制
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);
        }
    }
}

实现需要注意,添加和删除确实会终止,而且根本不存在循环依赖关系。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/43971700

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档