Uni/Bi direction X One/Many X Many/One Association

2019-09-15 17:28发布

问题:

Following question also refers to discussion in following questions as well https://stackoverflow.com/search?page=2&tab=Relevance&q=one%20to%20many%20unidirectional%20java

Best practise for adding a bidirectional relation in OO model

I tried to implementing 8 association combinations formed by [Unidirectional/Bidirectional] X [(One/Many) to (One/Many)] in Java. I found two cases can not be implemented namely Unidirectional One to One and Unidirectional One to Many (e.g. Person->*Vehicle). Other 6 combinations and Composition are possible programatically.

I Feel its not only the case with Java, these 2 cases do not exist. e.g. Use case - allocate one Aadhar/SSN number to only one person is possible if we know that number is not allocated to anybody else (reverse navigation is must). Does this mean we need to take care while making our design model not to arrive at these specific associations (though they might be present in analysis model)? I am confused on this.

回答1:

Basic (No Aggregation)

If you are looking at basic unidirectional association, then that's the simplest of them all.

Unidirectional One to One

class Person {
    String name;
}

Unidirectional One to Many

class Person {
    List vehicles;
}

Composite Aggregation

If I assume that you are asking about composite relationshions (where one SSN can be assigned to at most one person), then you can still implement it.

How exactly you decide to implement it is however subject to your specific domain or e.g. how you store your data, because

reverse navigation is must

is not actually true, because you can just check all Person instances; or you can store all the SSNs in a smart data structure that allows you to quickly check if a new one is unique, and then you would assign it to the Person without additional checks, because you already know that it is unique).

Or you can implement also the opposite lookup, which is not prohibited even if the association is "uni-directional"

To quote the UML Specs (11.5.3.1 Associations) [emphasis mine]:

Navigability means that instances participating in links at runtime (instances of an Association) can be accessed efficiently from instances at the other ends of the Association. The precise mechanism by which such efficient access is achieved is implementation specific. If an end is not navigable, access from the other ends may or may not be possible, and if it is, it might not be efficient.


Update from comments

Noone claims that upholding the relationship constraints has to be done in the accessors. In fact pretty much always you will have temporarily invalid relationships, imagine:

person = new Person();
// right now person is invalid state because it doesn't have an SSN
ssn = ssnGenerator.createNew();
// now ssn is also in invalid state because it has no person
person.setSSN(ssn);
// only now is person and ssn valid

(creating a constructor wouldn't help, because constructor is called after the object has already been created (so another part of the constructor could need the ssn already set).

So it is the responsibility of the programmer to ensure that the system upholds all constraints in whatever way it makes most sense. Using constructors/accessors is the easiest way in some circumstances, but you could e.g. wrap the code above in an atomic transaction. After all, if you kept your validation in the setSSN(), then what would happen if the programmer were to forget to call the method at all?

(person 1->* vehicle) p1.add(v1) and p2.add(v1) are possible violations

You asked about "person ->* vehicle", now you've changed it to "person 1 -> * vehicle" so obviously the answer differs. But the same principle as above applies -- it is the responsibility of the system to uphold all constraints, and wherever that's done in accessors, validation methods, or the way the system constructed is an implementational detail -- there's no single best way, and there will be always trade-offs.