Profile,Stereotype,TaggedValue与OCL漫谈
起因
事情的起因是由于我需要在一篇文章中使用一个UML Profile for Design Pattern,就是在上一篇blog中提到的那个Profile。但是当我使用OCL来描述一些约束时,突然发现我不知道如何去取得PatternClass这个Stereotype中的TaggedValue的一个名字为role的值。并非我对OCL不熟悉,而是由于我对Stereotype和TaggedValue的精确关系不甚了解。于是我在qq群中求助,从而和阿飞展开了长达两个多小时的讨论,最后在他的帮助下总算略有所得,遂记之。
问题的描述
为了文章的完整性,我还是再简要描述一下那个UML Profile for Design Pattern[1],如下所示:
这个Profile中引入了三个Stereotype和三个标签值,其具体含义列表如下:
Stereotype |
Applies To |
Definition |
<<PatternClass>> |
Class |
指出这个Class是设计模式中的一部分 |
<<PatternAttribute>> |
Attribute |
指出这个Attribute是设计模式中的一部分 |
<<PatternOperation>> |
Operation |
指出这个Operation是设计模式中的一部分 |
TaggedValue表如下:
Tagged Value |
Applies to |
|
Name |
Value |
pattern |
<name[instance],role> |
<<PatternClass>> |
指出了被附着的class在名为name的设计模式实例instance中扮演了role这个角色。 |
pattern |
<name[instance],role> |
<<PatternAttribute>> |
指出了被附着的Attribute在名为name的设计模式实例instance中扮演了role这个角色。 |
pattern |
<name[instance],role> |
<<PatternOperation>> |
指出了被附着的Operation在名为name的设计模式实例instance中扮演了role这个角色。 |
具体的含义我已经在上篇blog中介绍过。
对于这样一个Profile,我希望在使用OCL描述约束时,能够对于TaggedValue中的name、instance和role的具体值有所规定。例如一个具体的类MyDAO,它的Stereotype和标签值如下:<}>>。如果我希望有一个约束,表明MyDAO类的TaggedValue的role必须是DataAccessObject。则OCL如下:
context MyDAO inv:
??????
问题就在于如何使用OCL来描述这个与Stereotype和TaggedValue相关的约束。因为对于Class、Stereotype和TaggedValue的关系不甚明了。
问题的讨论
问题的讨论是非常烦杂的,我偷个懒,把聊天记录整理上来:
wxb_nudt 19:48:35
有这么一个OCL的问题。
wxb_nudt 19:49:38
一个Class,它有一个Stereotype(PatternClass),并且这个Stereotype有一个TaggedValue,如何在OCL表达式中引用这个标签值的值?
wxb_nudt 19:49:48
是不是
Class inv:
self.stereotype.taggedvalue.value?
wxb_nudt 19:51:53
老阿飞,出来跟俺讨论一下吧,只有你通读过UML2.0规范吧?
阿飞外传 21:42:29
上面的是UML1.x的元模型吧
wxb_nudt 22:06:15
能说说我那个OCL应该怎么写么?
阿飞外传 22:11:45
wxb_nudt 22:13:09
让我看看啊
wxb_nudt 22:14:09
modelElement可以直接引用stereotype
wxb_nudt 22:14:48
但是steretype可以直接引用taggedvalue么?stereotype是modelElement的一种么?
wxb_nudt 22:14:53
好像是的。
wxb_nudt 22:15:11
那么应该是class.stereotype.taggedvalue.value!
wxb_nudt 22:15:27
是不是啊?阿飞?这个图哪儿来的?
阿飞外传 22:19:04
modelElement可以直接引用stereotype --- right
但是steretype可以直接引用taggedvalue么?--- sure, but will go through TagDefinition
stereotype是modelElement的一种么? --- right
阿飞外传 22:21:04
是不是啊?阿飞?这个图哪儿来的? --- UML1.4 semantic01-09-73
阿飞外传 22:22:21
The data value of a tagged value must conform to the data type specified by the “tagType”
attribute of the tag definition.
-- cannot be specified with OCL (requires an OCL function that
converts a string name into a corresponding metatype)
阿飞外传 22:29:26
一个Class,它有一个Stereotype(PatternClass),并且这个Stereotype有一个TaggedValue,如何在OCL表达式中引用这个标签值的值?
inv:
self.taggedValue->forAll(v | v.dataValue = "theStringRepresentationOftheValue" imples v.type.tagType ="the
TypeName")
wxb_nudt 22:45:14
wait
wxb_nudt 22:47:23
<>:
self.taggedValue.value.name -> notEmpty
这是一篇文章中的。
wxb_nudt 22:49:25
对于一个class,不需要引用Stereotype,直接使用self.taggedValue可以么?这个TagValue是附加在这个Stereotype上面的。
wxb_nudt 22:51:55
对于String类型的值,应该可以直接这样得到
self.taggedValue.theStringRepresentationOftheValue
wxb_nudt 22:52:20
错了,应该是self.taggedValue.theValuename
阿飞外传 22:53:55
阿飞外传 22:55:16
http://www.erp5.cn/forum/dispbbs.asp?boardID=3&ID=329&page=1
wxb_nudt 22:55:22
看看
阿飞外传 22:57:29
<>:
self.taggedValue.value.name -> notEmpty
这是一篇文章中的。 --- 很可能是不正确的。
wxb_nudt 22:58:11
嗯,难道现在的UML2.0规范中没有很明确的指出这些关系么?就像上面这张图一样的?
wxb_nudt 22:59:28
还有一个问题
wxb_nudt 23:00:18
taggedValue可以附加于每一个模型元素。如果一个Class,有一个Stereotype扩展了它,这个Stereotype有一个标签值,那么这个标签值是否同时属于这个class?
阿飞外传 23:00:53
对于一个class,不需要引用Stereotype,直接使用self.taggedValue可以么? --- 可以,也是profile的语用之一。
这个TagValue是附加在这个Stereotype上面的。----- TagValue与Stereotype没有什么包含关系, 一个TagValue的定义(TagDefinition)只是从值(TagValue)到型的一种声明,是一种由值到类型的自底向上的宣告式分类方法。
wxb_nudt 23:02:27
有点明白了,Stereotype和TagDefinition都是用来定义类型的,通俗的说。
而Class和TaggedValue就是这些类型的实例,是不是这样的?
wxb_nudt 23:02:55
因此,从Class直接引用TaggedValue是很自然的。
阿飞外传 23:05:40
taggedValue可以附加于每一个模型元素。如果一个Class,有一个Stereotype扩展了它,这个Stereotype有(只是偶然关联而不是"有")一个标签值,
那么这个标签值是否同时属于这个class?--- 标记值属于某个class,并不是Stereotype or TagDefinition使然,完全是用户不小心加到某个class上的乱帖的小标签,至于这个标签,有什么有分类完全是另一回事。
阿飞外传 23:06:34
至于这个标签,有没有分类,是什么分类完全是另一回事。
阿飞外传 23:06:53
这是动态类型(分类)面向的。
阿飞外传 23:07:19
或者说是:值面向的
阿飞外传 23:08:37
或者说:值就是存在,并不需要类型的存在而存在。
wxb_nudt 23:10:00
似乎有点明白了。
阿飞外传 23:10:26
因此基于profile机制的UML元对象(M2级物理实例)的(虚)slot可以动态扩张的
阿飞外传 23:11:39
这是由(ModelElement, taggedValue)关联建立起来的
wxb_nudt 23:12:16
意思就是说,在模型元素上面,可以附加任意的值,这些值就用tag value来表示就可以了。
阿飞外传 23:13:51
对UML::ModelElement而言相当于这样:
class UML::ModelElement { List tagValue; //(虚)slot扩展点 }
阿飞外传 23:14:04
对。
wxb_nudt 23:14:10
嗯,现在明白了。
wxb_nudt 23:14:19
thank you。
阿飞外传 23:15:17
class UML::ModelElement {
List stereotypes ; //(虚)子类型扩展点
List tagValue; //(虚)slot扩展点
}
阿飞外传 23:16:23
class UML::ModelElement {
List stereotypes ; //(虚)子类型扩展点
List tagValue; //(虚)slot扩展点
}
wxb_nudt 23:16:25
每个Class只能有一个Stereotype的,所以不应该用 List stereotypes ;
wxb_nudt 23:16:49
因为后来的Stereotype会替换前面的。
阿飞外传 23:17:09
每个Class只能有一个Stereotype的 --- 每个类不可能有多个子类?
wxb_nudt 23:17:10
UML2.0是这样的,我不知道前面的规范如何。
wxb_nudt 23:17:19
我刚刚读过。
wxb_nudt 23:19:43
找不到了,不过我记得是这样的。
阿飞外传 23:20:16
wxb_nudt 23:21:59
可能我的方向搞反了,对于Remote和Home,它们都扩展了Interface,而对于Interface,它可以扩展为多个Stereotype。
wxb_nudt 23:22:22
我的意思是,一个具体的Class,只能拥有一个Stereotype。
wxb_nudt 23:22:36
你的意思是,一个模型元素可以扩展为多个Stereotype
wxb_nudt 23:24:29
在一个系统中,这么写:
class UML::ModelElement {
List stereotypes ; //(虚)子类型扩展点
List tagValue; //(虚)slot扩展点
}
是正确的。因为它代表这个系统中的某个模型元素扩展了哪些内容。
阿飞外传 23:25:02
一个具体的Class,只能拥有一个Stereotype。 --- 因为OO的用户级(M1)一个用户设计对象只能归属到一个分类。
一个模型元素可以扩展为多个Stereotype --- 因为M2的类型系统中,一个类可以有多个子类。
wxb_nudt 23:25:17
我的意思和你一样。
wxb_nudt 23:26:38
TagDefinition中的TagType:Name
Name是一个数据类型么?
阿飞外传 23:27:03
TagDefinition中的TagType:Name
Name是一个数据类型的名字
wxb_nudt 23:28:51
Tagged Value Applies to
Name Value
pattern <> 指出了被附着的class在名为name的设计模式实例instance中扮演了role这个角色。
wxb_nudt 23:29:14
这样一个TagValue,它的TagType的值是什么?
wxb_nudt 23:30:45
我对TaggedValue和TagDefinition的关系感到很迷惑。
阿飞外传 23:31:11
Tagged Value Applies to
Name Value
pattern <> 指出了被附着的class在名为name的设计模式实例instance中扮演了role这个角色。--- 这是一张表么,看不太清楚,能帖一图么。
wxb_nudt 23:31:20
wait
wxb_nudt 23:31:36
阿飞外传 23:35:09
相当于:
struct PatternAtt { String name; String role }
class PatternClass
{
PatternAtt pa;
}
wxb_nudt 23:36:04
其实我就想知道如何在OCL中表达role的取值。
阿飞外传 23:38:13
它能给出具体的例子么
wxb_nudt 23:38:53
这么一个类 <}>>ConnectionPool
wxb_nudt 23:40:02
显然它的TaggedValue的两个值是name=Abstract Factory,role=AbstractFactory
stereotype=PatternClass
阿飞外传 23:42:31
[instance]是什么
wxb_nudt 23:42:56
它可以不出现,你忽视它好了。
阿飞外传 23:43:34
(前面我说的有误,确实可以从作为导航入口点,导航到TaggedValue)
wxb_nudt 23:44:39
怎么导航呢?
wxb_nudt 23:45:57
Class、Stereotype、TagDefinition、TaggedValue?
阿飞外传 23:47:00
因为Stereotype 继承自GeneralizedElement,后者继承自ModelElement,而ModelElement有到TaggedValue的包括关联。
wxb_nudt 23:47:44
那就是可以直接从Class到Stereotype然后到TaggedValue
wxb_nudt 23:48:14
这个问题解决了,但是如何表达那个role的取值呢?
wxb_nudt 23:50:06
it's a big problem.
wxb_nudt 23:55:16
主要问题是如何从dataValue中取得role的值?
阿飞外传 23:55:14
context PatternClass inv:
self.stereotype.definedTag->forAll(td : TagDefinition |
td.tagType = "AbstractFactory" imples td.typedValue.dataValue ="Abstract Factory[instance],AbstractFactory") and
self.stereotype.definedTag->forAll(td : TagDefinition |
td.tagType = "Iterator" imples td.typedValue.dataValue ="Iterator [instance],Iterator") and
...
阿飞外传 23:55:47
需要串的操作设施。
wxb_nudt 23:57:22
我认为td.tagType = "Pattern"
wxb_nudt 23:59:39
主要问题是如何从dataValue中取得role的值?
role这个名字不是白定义了的。
阿飞外传 00:05:18
因为这个paper把这些信息用串记录在TaggedValue的dataValue字段中,所以需要串处理。你可以用其它方式(actually, i am not sure,maybe more detailed stereotype or taggedvalue)
wxb_nudt 00:10:57
好吧,谢谢你了,我明天再仔细研究吧,晚安阿飞!
结论整理
结论一,UML的扩展机制
首先,对于Stereotype和标签值的扩展机制,显然下面这个式子是成立的:
class UML::ModelElement {
List stereotypes ; //(虚)子类型扩展点
List tagValue; //(虚)slot扩展点
}
它表明,对于某个UML的模型元素,可以扩展为不同的Stereotype,也可以附加很多的标签值。有两点需要注意的是:第一,对于某个具体的模型元素,它只能属于一个Stereotype;第二,对于某个模型元素的标签值,标签值的名字是唯一的。也就是说,如果某个模型元素有多个标签值,并且它们的名字相同,那么它们是同一个标签值。
结论二,模型元素、Stereotype和TaggedValue的导航关系
通过观察上面的图可以得知:Class和Stereotype都属于模型元素,它们都可以直接通过taggedValue导航到自己拥有的标签值。另外,Class可以通过stereotype导航到自己所属的构造型。
结论三,TaggedValue和TagDefinition的关系
TaggedValue只有一个属性,就是dataValue,它是一个String[*],可以包含字符串数组。所有的标签值的值都存储在这个dataValue中。
而TagDefinition是标签值的数据结构的描述,它有两个属性,tagType:Name,和mutiplicity:Mutiplicity。Name和Mutiplicity都是数据类型,它们联合起来定义了TaggedValue的数据结构。
TaggedValue和TagDefinition之间可以通过type和typedValue来互相导航。
结论四,如何表达tuple形式的TaggedValue
这是昨晚没有解决的问题,但是今天在一篇文章[2]中看见了相应的例子。
<>:
self.baseClass = Class and self.taggedValue -> exists
(tv:taggedValue | tv.name = "pattern" and tv.dataValue =
"tuple")
对于一个tuple来说,可以直接取值他的一个部分,就使用这个部分的名字即可。
因此可以这样得到role的值:
class.stereotype.taggedValue.dataValue.role
那篇文章中的一个表达式证实了这一点:
<>:
self.taggedValue.dataValue.role -> notEmpty
问题的解决
一个具体的类MyDAO,它的Stereotype和标签值如下:<}>>。我希望有一个约束,表明MyDAO类的TaggedValue的role必须包含DataAccessObject角色。则OCL如下:
context MyDAO inv:
self.stereotype.taggedValue.dataValue.role->exists(“DataAccessObject”)
Reference
[1]. Extending UML To Visualize Design Patterns In Class Diagrams
[2]. Visualizing Design Patterns With A UML Profile