Invariant Constraint :: Dominoo

来源: BlogBus 原始链接: http://www.blogbus.com:80/blogbus/blog/diary.php?diaryid=420664 存档链接: https://web.archive.org/web/20050113025441id_/http://www.blogbus.com:80/blogbus/blog/diary.php?diaryid=420664


Dominoo Design Of Model IN Object-Oriented <<<Dominoo | 首页 | 再谈Invariant Constraint>>> Invariant Constraint 时间: 2004-10-02 o Basic Concept 一个Class可以有它自己的Invariant Constraints.它们被用来检查一个Class是否符合契约(Contract). 什么是契约,先来看一看牛津英语辞典对其所做的定义: An agreement between two or more parties, especially one that is written and enforceable by law. 对于class得invariant constraints而言,契约是Class instance和其使用者之间的Agreement. Class instance是service provider,而使用者是clients.如果clients想使用某个class的service,它们就必须遵守这些constraints.否则,将造成这个class的某个或所有的instance处于invalid状态.从而让整个系统失效. Invariant Constraints的不变性体现在Class/Class Instance由于外部(Clients)对其发送消息的前后,我们可以用表达式描述为: {INVs} public operation {INVs} 即,当外部调用其public operation(发送消息)之前,应该检测Class/Class Instance是否处于合法的状态.由于一个operation可能会改变Class/Class instance的状态,所以在public operation被调用之后,也应该检测其是否处于合法状态. 但在一个operation被调用期间,这些Invariant Constraints不必要被遵守. 我们来看一下一个class instance的Lifecycle.

  1. 被创建 (Constructor被调用)
  2. 接收外界发送的消息. (其它函数被调用)
  3. 被销毁 (Destructor被调用) 在一个class instance被创建之后,就应该满足invariant constraints. 随后,每次当其接受外部消息之前,以及消息处理之后都要检测这些Constraints.在被销毁之前,没有必要再检测此class instance是否合法,很有可能destroy它的原因就是因为其不满足自身的约束. 以下图为例,当一个class instance被创建之后,则处于状态I,随后等待clients给它发消息.收到一个消息后进入状态1,然后再收到一个消息后进入状态2,随后又由于另外一个消息而进入状态3,随后被销毁.图中的箭头表示外部消息的处理过程,所以其invariant constraints需要在进入状态I,1,2和3处之前进行检测,并在状态I,1和2之后进行检测. Create Destroy -------->(I)---->(1)----->(2)---->(3)--------->(X) 从这个图中,你可能会产生一个疑问,你或许认为并没有必要在一个外部消息被处理前后都检测invariant constraints,因为在一个连续的调用过程中,上一次的外部消息处理结束时的状态就等于下一个外部消息处理之前的状态,所以只需要在外部消息处理之后进行检测即可. 但实际的情况是,一个class instance可能会调用自身的public operation,比如: class A{ public void op1() { ... } public void op2() { ... op1(); ... } }; 当外部调用op2时, op2经过一些其它处理之后,会调用op1, 由于在调用op1之前,系统状态可能已经发生了变化,所以控制流进入op1的时候,并不等于上一次外部消息处理结束时的状态.只有在调用op1之前也同样进行检测,才能保证系统的安全. 看到这个例子,你可能仍然不服气,因为,理论上,op2调用op1的过程是一次内部处理过程,这期间系统可以不用进行检测.甚至你会建议在这样的情况下,op1调用之后都无需检测. OK,我们看另外一种情况: class A{ private B b = new B(this); public void op1() { ... } public void op2() { ... b.op(); ... } }; class B{ private A a; public B(A pa) { a = pa; } public void op() { ... a->op1(); ... } }; 在这个例子中,class A与class B之间有一个1对1的关联,在class A的op2中,调用了class B的op,在class B的op中,调用class A的另外一个外部操作op1,对于class A的instance来说,class B的instances绝对是外部实体.所以对于任何public的operation,都应该在调用之前和之后均进行检测. o Query Operation 类型为Query的public operation除外,因为Query operation不会对系统状态造成任何改变,所以在query operation执行之后无需重新进行检测,只需要在之前检测即可. o Class Scope Operation 一个class可以有class scope的operation,由于这些operation不会发给任何一个instance,所以在调用这些operation的时候,也无法进行invariant constraints的检查。 一个solution是在定义invariant constraits的时候,把它们分类为Instance scope和class scope的;另外一个solution是我们可以把这些class scope的invariant constraints放到class scope operation的post condition里.前者相对于后者的好处是: 我们无需把相同的约束在每个class scope operation的post condition里重新定义一遍;缺点是: OCL没有区分invariant constaits的scope,我们必须自行扩展OCL。 o Visibility 由于Invariant Constraints是一个class instance和其clients之间的一种契约,所以无需在private和protected的operation里进行检测. 更重要的原因是: 所谓Invariant Constraints是指当外部消息被处理之前和处理之后class instance所应该处于的状态,在消息被处理期间,这些Constraints并无必要遵守。所以,对于private,protected的operation,如果进行Invariant Constraints的检测,可能会造成系统失效。 o Attributes 对于Attributes,按照严格的OO理念,应该完全设置为Private的,然后提供set/get operation,这些set/get operation的visibility被设置为相应的值.其中public set operation可能会改变系统的状态,也应该在其中进行Invariant Constraints检测. darwin_yuan 发表于 2004-10-02 15:34 引用(Trackback0) | 编辑 评论 发表评论 最后更新 相等性判断的自动化 Link操作 在GC系统上的Destroy语义 Composite的约束 再谈Invariant Constraint Invariant Constraint Dominoo