1

Suppose that there is one container C that can contain objects of type A and B. C cannot be empty and can only contain 1 object of each type. That means that C contains one of the following:

  • 1 object of type A
  • 1 object of type B
  • 1 object of type A + 1 object of type B

To map this problem in UML class diagram I tried these...

enter image description here

... but none of them map the problem since that in the left diagram the container C can be empty and in the right diagram the container C can contain two objects of type A (or B).

So my question is: how is it possible to map this problem?

4

2 回答 2

1

In the left diagram, the cardinalities allow - 1 object of type A - 1 object of type B - 1 object of type A + 1 object of type B - no objects

Cardinalities affect only the multiplicity of the association end where they apply. You need to write the last part of the condition (at least one A or at least one B) as a constraint (invariant). An invariant is a condition that always holds for every instance of that class.

If you write the constraint as pseudocode, it is enough to say that a!=null or b!=null. You draw the invariant as a note with stereotype «invariant» attached to the constrained class.

Constraint

In OCL (a language used for non-ambiguous description of constraints):

 inv: not a.oclIsUndefined() or not b.oclIsUndefined()

(You can read more about OCL here)

The right diagram introduce a super-class Object that is not part of the description of your problem. There could be another classes that specialize Object (e.g. C) that you don't want in your association. In this case the invariant is more complex, because you need to require that:

  • There is at most one instance of A
  • There is at most one instance of B
  • There are no instance of other classes.

(If you write the invariant in natural language, it is enough to mention the items above).

In OCL, assuming that the association end is named x, the invariant reads:

inv: x->select(oclIsKindOf(A))->size()<=1 and
     x->select(oclIsKindOf(B))->size()<=1 and
     x->select(not oclIsKindOf(A) and not oclIsKindOf(B))->isEmpty()

or

inv: let a:Integer = x->select(oclIsKindOf(A))->size() in
     let b:Integer = x->select(oclIsKindOf(B))->size() in
     a<=1 and b<=1 and x->size()=a+b
于 2013-03-21T01:39:38.773 回答
1

The solution to your problem is indeed using UML constraints as explained by Javier. But in this particular case, there is a predefined UML constraint called {or} that does exactly what you want. The "or" constraint is predefined in UML and can be graphically written between associations. Note how 0 is removed from the multiplicities because {or} means that one of the aggregations may not be present at all.

enter image description here

P.S 1: For a similar example on {xor} see page 302 and 303 of UML 2.0 Toolkit by OMG Press Book.

P.S 2: As far as I know, the notation you are using that branches an aggregation is not correct UML notation (or at least has a different meaning). Joining together multiple relationships is an alternate notation applicable to generalization.

P.S 3: Of course you could use OCL or natural language for your constraint if you find it more descriptive.

于 2013-03-21T03:43:52.207 回答