10.3 Complex Constraints

Complex constraints involve multiple objects and their links,
and capture more complex rules than are shown in the previous section
on simple constraints. Multiplicity constraints are a special case of
complex constraints in that they have their own notation; you do not
need to capture multiplicity constraints using the OCL.

Multiplicity notation is used in Figure 10-1s class diagram to define
multiplicity rules that must be respected. One such constraint states
that a project relates to a single organization and to a single team.
Figure 10-3 shows an object diagram that is invalid
because it violates those rules.

Figure 10-3. Invalid relationships between organizations, a project, and teams

The UML's multiplicity notation captures rules
regarding the number of objects that may be related to one another.
However, using the OCL, many other complex rules may be expressed
using constraints.

You could capture multiplicity constraints using the OCL, but instead
you should use the notation for such constraints already built into
the UML.

Figure 10-1 shows the details about organizations,
projects, teams, and people, but does not indicate whether a project
and its team must relate to the same organization, nor does it
indicate whether a team and its members must relate to the same
organization. Using the OCL, it's possible to create
a complex constraint that enforces the rule that a project, its team,
and all the team members must belong to one organization.

Figure 10-4 shows a project and a team that relate
to one another and to two different organizations. This would allow a
team to work on a project for another organization, which most
organizations don't allow! Let's
look at how we can use the OCL to prevent the situation in Figure 10-4 from occurring.

Figure 10-4. Relationships between organizations, a project, and a team

There are multiple expressions to show that a project and a team that
relate to one another must relate to the same organization.

Within the context of a team, I can use the following expression to
assert that the project's organization must match
the team's organization:

self.project.organization = self.organization

Coming at it from the other direction, within the context of a
project, I can use the following expression to express the same rule:

self.team.organization = self.organization

Within these expressions, the keyword self is
optional and the expressions on either side of the
= symbol may be interchanged. For example, the
following two expressions produce identical results:

The following rule ensures that every project related to an
organization's team is related to the same
organization:

organization.team->forAll (t : Team | t.project.organization = self)

Notice that the self keyword is not optional in
these two expressions because it is the only way for an organization
object to refer to itself.

Figure 10-6 illustrates another potential problem,
showing a team and a person that relate to one another but that also
relate to two different organizations. This allows a person to work
on a team for another organization, which most employers
don't allow! Thus, we reasonably might want to write
a constraint prohibiting the situation.

Figure 10-6. Relationships between organizations, a team, and a person

Consider how a team and a person relate to one another. For example,
a team and a person that relate to one another ought to relate to the
same organization. Within the context of a team, I can use one of the
following expressions to capture this rule between teams, people, and
their organization:

Again, within these expressions, the keyword self
is optional and the expressions on either side of the
= symbol may be interchanged. You cannot
interchange expressions on either side of the <
or > symbols.

The multiplicities discussed in the previous section and the rules
discussed in this section make the model more precise in representing
how organizations, projects, teams, and people are related to one
another.