OCL简明手册
以下内容以[1]为蓝本,加入一些个人观点及[2]的内容,水平有限,敬请指正。
Navigability:

图1
-----------------------------------------------------------------------
context Company::getEmployees() : Set(Person)
body: self.employee
解释:定义Company类的成员方法getEmployees。通过关联端(employee)返回与self(类型为Company)关联的所有employees(类型为Set(Person))。
就OCL风格而言,若某关联端的重数(multiplicity)>1,则应将关联端的角色名改为复数形式,故图1中的关联端employee改为employees会更好,这样,当写下self.employees,我们就知道表达式是一个收集(collection)类型(其对应的收集方法调用有一个前缀"->"),而不是对象类型(其对应的方法调用使用前缀"."),示意代码如下:
self.employees->forAll/exists/intersection/union/...--收集操作
self.employee.attributeName/methodName()/forAll/exists/intersection/union/...--属性/方法/收集操作
OCL中收集类型有4个子类型:Set(集合),Bag(包:多重集),OrderSet(有序集合),Sequence(有序包)。
-----------------------------------------------------------------------
context Person ::getShareholders() : Bag(Shareholder)
body: company.shareholder
解释:定义Person类的成员方法getShareholders。方法体返回展平化的Bag,结果类型为Bag(Shareholder)。在语法上,company.shareholder等价于self.company.shareholder等价于self.company->collect(c: Company| c.shareholder)等价于self.company->collect(c | c.shareholder)。
只有使用特定的收集操作(collectNested)才能产生嵌套的收集。在默认情况下(使用"collect"或".")OCL表达式中的收集子类型实例的成员不可能是集合,只是对象引用或值。
当使用"."或"collect",迭代超过一个收集子类型实例的所有元素时就会产生类型为Bag(元素类型)的多重集,本例的示意图如下:
图2
产生的结果是Bag{shareholder1,shareholder2,shareholder1,shareholder1,shareholder2}。 OCL定义了一个收集操作asSet(),可将Bag转换为Set,如上述方法定义可写为:
context Person ::getShareholders(): Set(Shareholder)
body: company.shareholder->asSet()
在OCL2.0中,company.shareholder应写为Company.Shareholder,即若关联端没有角色名时,使用关联端所连接的类型名作为导航的替代。
-----------------------------------------------------------------------
基本逻辑项:not, ture, and, implies(蕴含)等
量词(前缀为:"->"): forAll, exists 等
常用收集操作(前缀为:"->"):select(bool expression), isEmpty()/notEmpty(), size(), includes(用于判定收集是否包含元素), includeAll(用于判定收集是否包含收集), union, intersection, including(为收集增加元素)
-----------------------------------------------------------------------
context Shareholder
inv: company->forAll(c | c.employee->select(birthplace = #
解释:本不变式(类型必为Boolean)陈述的事实是:
就每一shareholder而言,有下述断言:
对该shareholder所控制的每一个company,又有下述断言:
该company的所有出生地为Paris的员工所组成的集合不为空。
#为枚举类型所定义的常量的前缀,从而在语法上,将枚举常量与类的属性区分开。
在[2]中,枚举类型可由用户使用stereotype为<<enumeration>>标记来定义枚举类型,且使用"类型名::枚举值"方式引用。
-----------------------------------------------------------------------
操作规范中的部分操作符:
oclIsNew():仅用于后置条件的定义中,以断言某对象被new出来了。因为在OCL中任何表达式都是OclAny类型的子类型,而oclIsNew为OclAny的成员方法,故oclIsNew可用于任何对象。
@pre:仅用于后置条件的定义中,作为后缀,以获取所标记的某对象在其成员方法执行前的值。如:
context Company::newEmployee(p : Person) : Boolean
pre: not employee->includes(p)
post: employee = employee@pre->including(p)
-----------------------------------------------------------------------
与类型特征有关的部分操作符:
oclIsTypeOf:测试对象的准确类型,如:employee.oclIsTypeOf(Employee)求值为true,employee.oclTypeOf(EmployeeSuper)求值为false,这里假设EmployeeSuper为Employee的任何(级的)父类型。
oclIsKindOf:测试对象的兼容类型 ,将上述2式中的oclIsTypeOf换为oclIsKindOf后,求值均为true。
下式是跨越:M0, M1, M2的类型判定操作:
context Person inv: self.oclIsType(Person) = true and
Person.oclIsType(Classifier) = true and Person.oclIsKindOf(ModelElement)= true
见下图表示:(这里oclIsType相当于instanceOf关系)
ModelElement
|
/_\
|
Classifier
|
/_\
|
Class -------M2
|
instanceOf
|
Person -------M1
|
instanceOf
|
self -------M0
-----------------------------------------------------------------------
[1]Franck Barbier. Formalization of the Whole-Part Relationship in the Unified Modeling Language. IEEE TRANSACTIONS ON SOFTWARE ENGINEERING, VOL. 29, NO. 5, MAY 2003
[2]Anneke Kleppe. Object Constraint Language, The: Getting Your Models Ready for MDA, 2/e. Addison Wesley, 2003
浙公网安备 33010602011771号