管理Java模型中的双向关联

4
我有一个Java模型,其中类之间存在关联(1对1、1对n、n对n),应该在双向上工作。
例如:类A具有类B的集合。
所有B的实例都必须知道其父项(A)是谁。如果我更改B的父属性,则还需要在另一侧更新关联。
我认为编写代码以使两端的关联保持最新非常繁琐且容易出错。
那么:有没有更好的方法?是否有Java库可以管理两个对象之间的双向关联?

1
我认为编写代码,以保持两端的关联最新是相当繁琐和容易出错的。你为什么这么说?通常这并不难。 - John Kugelman
这很繁琐,因为我必须将相同的功能添加到所有模型类中。我觉得这是非常重复的工作。这容易出错,因为我必须记住一些特殊情况。例如,如果我将B的父级设置为A的另一个实例(将B从一个A转移到另一个A),我必须确保删除旧链接。但是如果我第二次设置相同的父级呢?那么代码就不应该触及已经存在的链接。等等。当然,要做对并不是不可能的,但如果已经有解决此问题的解决方案,为什么要重新发明轮子呢? - Damian
2个回答

5
另一种方法是将关系移出所讨论的对象。很多时候,A和B都不需要彼此了解;使用代码发现这些属性方便。这就是图形或双向映射(bidirectional maps)可以发挥作用的地方。
双向映射可以轻松地用于跟踪一对一的关系。图表可以更好地跟踪其他类型的基数(多对一、多对多等)。
有几种不同的图表实现可以帮助解决问题。我听说过但从未使用过JGraphT,还有一个我经常使用的叫做plexus(与IOC容器无关)。分别是 http://jgrapht.sourceforge.net/http://plexus.sf.net/
图表很好,因为它允许完全灵活地定义不同的关系,并隐式地维护双向链接。
事实上,两个关系的双方都需要保持同步,这通常意味着关系本身与端点的重要性相等,而不是每一方都应该尝试封装。
然而,如果父母和孩子真的需要彼此操作,那么一种方法是找出哪个是主要的,并确定是否所有操作都可以通过该对象完成。例如,在父子关系中,可以在父对象上进行子对象操作,并在此操作期间将对自身的引用传递给子对象。我认为,如果不能这样做,则这是设计中需要重新考虑的一个好指标。
再次使用父子示例,我真的没有找到过父->子和子->父关系如此动态的情况,以至于一端无法控制它。而且99%的时间,我保持从次要到主要的反向引用仅仅是为了方便,而且关系的生命周期已经被很好地建立了。
否则,我就使用图表。

2
你有三个选择:
  1. 管理这个关系的两端;
  2. 使其有效地双向。我的意思是它是单向的,但通过代码有效地变成了双向的;或者
  3. 面向切面编程。
例如2中的一个例子是,你有一个House和Room之间的一对多关系。Room有一个对House的引用。你可以在House中维护一个Room列表,或者做一些类似以下的事情:
public class House {
  ...

  public List<Room> getRooms() {
    List<Room> ret = new ArrayList<Room>();
    for (Room room : /* list of ALL rooms */) {
      if (room.getHouse().equals(this)) {
        ret.add(room);
      }
    }
    return ret;
  }
}

在某些情况下,执行此操作的性能损失是合理的。

使用(3)可以使用面向方面的编程(例如Spring AOP,AspectJ)在设置Room上的House时创建切入点以自动更新House。个人而言,我倾向于回避这种方法,因为您很容易陷入太多“魔法”的境地,这可能会令人困惑并成为调试的噩梦。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接