Managing bidirectional associations in my java model

前端 未结 2 1081
旧时难觅i
旧时难觅i 2020-12-19 18:44

I have a java model where the classes have associations (1 to 1, 1 to n, n to n) that should work in both directions.

Example: class A has a collection of class B

相关标签:
2条回答
  • 2020-12-19 19:37

    You have three options:

    1. Manage both ends of this association;
    2. Make it effectively bidirectional. By this I mean that it is unidirectional but it is effectively the other way via code; or
    3. Aspect-oriented programming.

    As an example of 2 is you have a one-to-many relationship between House and Room. Room has a reference to House. You could maintain a List of Rooms in House or do something like:

    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;
      }
    }
    

    There may be circumstances where the performance hit of doing this is justified.

    With (3) you can use aspect-oriented programming (eg Spring AOP, AspectJ) to create a pointcut on setting the House on Room to update the House automatically. Personally I tend to shy away from this approach as you can easily get in a situation of there being too much "magic", which can be confusing and a nightmare to debug.

    0 讨论(0)
  • 2020-12-19 19:47

    Another approach is to move the relationship out of the objects in question. Many times neither A nor B ever needs to know about each other; it's the using code that finds those properties convenient. This is where graphs or bidirectional maps can come into play.

    Bidirectional maps can trivially be used to keep track of one to one relationships. Graphs can be much better at keeping track of the other types of cardinality (many-to-one, many-to-many, etc.)

    There are a couple different graph implementations that could help on that end. I've heard of but never used JGraphT and there is one I've used a lot called plexus (no relation to the IOC container). http://jgrapht.sourceforge.net/ and http://plexus.sf.net/ respectively.

    A graph is nice because it allows complete flexibility in how different relationships are defined and the bidirectional link is maintained implicitly.

    The fact that both sides of the relationship need to keep themselves in synch is frequently a sign that the relationship itself is of equal importance to the endpoints and not something that each side should be attempting to encapsulate.

    Still, if parent and child really do need to operate on each other then one approach is to figure out which is primary and whether all operations can be done through that object. So, for example, in the parent child relationship can child operations be done on the parent with the parent passing a reference to itself to the children during that operation. I'd argue that if you can't then it is a good indicator that some lines need to be redrawn in the design.

    Again using the parent-child example, I haven't really found a case where the parent->child and child->parent relationship was so dynamic that one end couldn't control it. And 99% of the time that I keep a back-reference from secondary to primary, it's for convenience and the lifecycle of the relationship is well established.

    ...otherwise, I use a graph.

    0 讨论(0)
提交回复
热议问题