OCL简明手册

下文摘自我在mdaChina.net发的帖子:http://www.mdachina.net/forum/dispbbs.asp?boardID=22&ID=117&page=1

以下内容以[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 = #
Paris)->notEmpty())

解释:本不变式(类型必为Boolean)陈述的事实是:
就每一shareholder而言,有下述断言:
   
对该shareholder所控制的每一个company,又有下述断言:
       
company的所有出生地为Paris的员工所组成的集合不为空。

#为枚举类型所定义的常量的前缀,从而在语法上,将枚举常量与类的属性区分开。
[2]中,枚举类型可由用户使用stereotype<<enumeration>>标记来定义枚举类型,且使用"类型名::枚举值"方式引用。
-----------------------------------------------------------------------

操作规范中的部分操作符:

oclIsNew():仅用于后置条件的定义中,以断言某对象被new出来了。因为在OCL中任何表达式都是OclAny类型的子类型,而oclIsNewOclAny的成员方法,故oclIsNew可用于任何对象。

@pre:仅用于后置条件的定义中,作为后缀,以获取所标记的某对象在其成员方法执行前的值。如:
context Company::newEmployee(p : Person) : Boolean
pre: not employee->includes(p)
post: employee = employee@pre->including(p)
-----------------------------------------------------------------------

与类型特征有关的部分操作符:

oclIsTypeOf:测试对象的准确类型,如:employee.oclIsTypeOf(Employee)求值为trueemployee.oclTypeOf(EmployeeSuper)求值为false,这里假设EmployeeSuperEmployee的任何(级的)父类型。
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

posted on 2004-08-16 02:53  阿飞外传  阅读(1997)  评论(0)    收藏  举报

导航