7.5.3 属性:关联端和导航

从一个特定的对象开始,我们可以在类图上通过关联导航到另外的对象和它们的属性。为此,我们使用对面的关联端来对关联进行导航:

object.associationEndName

该表达式的值是associationEndName关联端对象的集合。如果该关联端的multiplicity是 0..1 或 1,则这个表达式的值是一个对象。在示例类图中,当我们从一个Company上下文开始(即self是Company的一个实例)时,我们可以写:

context Company
    inv: self.manager.isUnemployed = false
    inv: self.employee->notEmpty()

在第一个不变式中,self.manager是一个Person,因为其multiplicity是 1。在第二个不变式中,self.employee计算为一个Person集合。缺省的,导航将产生一个Set。当类图上的关联有 {ordered} 修饰时,导航将产生一个 OrderedSet。

像Set、OrderedSet、Bag、Sequence这样的集合在OCL中是预定义类型。它们都有大量的预定义操作。集合自身的属性使用 -> 后面跟属性名来访问。如下的示例在一个person上下文:

context Person inv:
    self.employer->size() < 3

这在集合self.emplyer上应用size属性,这将产生Person self的雇主数量。

context Person inv:
    self.employer->isEmpty()

这在集合self.employer上应用了isEmpty属性,这将在雇主集合为空时产生真否则产生假。

缺失关联名称

关联名永远不会缺失。如果没有一个显式的名称可用,就会按照UML风格指南构造一个隐式的名称。对于没有显式命名的关联,将采用如下的产生式规则来给定名称:

"A_"<association-end-name1>"_"<association-end-name2>

其中<association-end-name1>是一个关联端的名称,而<association-end-name2>是另一个关联端的名称。

缺失关联端名称

关联端的名称永远不会缺失。如果没有一个显式的名称可用,那么就会隐含的取该端所附加到的类的名称。

图7.2 Ambigous name example

这将导致在一个隐式的关联端名称和另一个显式的名称之间产生二义性,除非只有一个关联端是可导航的。这种二义性的名称不能用在OCL中。

aPerson.role --存在二义性

使用关联名限定关联端

可以通过使用关联的名称或它的源分类符的名称来限定关联端从而消除歧义。

aPerson.Person::role            --仍然歧义
aPerson.A_person_role::role     --使用隐式的Person到Part的关联名称来指代一些Parts
aPerson.A_owner_role::role      --使用隐式的Person到Role的关联名称来表述一个Role

关联拥有的端

在一个UML关联中,一个端可以被另一端的分类符所有,也可以被该关联自身所有。在OCL中这种属主关系并不重要。无论哪种情况,该关联端都可以被认为是分类符的一个属性,并且可以从该端导航到其它地方。

在Mulitiplicity为0或1的关联上导航

因为manager角色的multiplicity是1,所以self.manager是一个Person类型的对象。这样的一个对象也可以通过使用oclAsSet()或它的"->"简化来当做集合使用。其行为就如同一个只包含一个元素的集合。作为集合的用法要通过一个箭头后跟集合属性来完成。如下示例对此做了展示:

context Company inv:
    self.manager->size() = 1

上面的self.manager子表达式用作一个集合,因为它使用了箭头来访问集合上的size属性。该表达式计算为真。

context Company inv:
    self.manager->foo

上面的self.manager子表达式用作一个集合,因为它使用了箭头来访问集合上的foo属性。该表达式不正确,因为foo不是一个定义在Set上的属性。

context Company inv:
    self.manager.age > 40

上面的self.manager子表达式用作一个Person,因为使用点号来访问Person的age属性。

对于一个可选关联(multiplicity为0..1),在对关联进行导航的时候检查对象是否存在非常有用。示例中,我们可以写:

context Person inv:
    self.wife->notEmpty() implies self.wife.gender = Gender::female

组合属性

属性可以合并起来形成更为复杂的表达式。一条重要的规则是OCL表达式总是计算为一个特定类型的一个特定对象。在获得一个结果后,建模者总是可以在该结果上应用另一个属性来获得一个新的结果值。因此,每个OCL表达式都以从左到右进行读和计算。

如下式示例类图中使用组合属性表示的一些不变式:

[1] 已婚人士的年龄大于等于18

context Person inv:
    (self.wife->notEmpty() implies self.wife.age >= 18) and
    (self.husband->notEmpty() implies self.husband.age >= 18)

[2] 公司最多有50名员工

context Company inv:
    self.employee->size() <= 50

results matching ""

    No results matching ""