一、Sequence
Diagram
Interaction diagrams 描述了一组对象之间的交互行为。其中最常用的就是 sequence
diagram。
Sequence diagram 只是捕捉了一个特定场景中的交互情况,它使用 Use case 描述了一些实例对象以及它们之间消息的传递。
Interaction diagrams 并不能用于表示算法的细节、循环处理以及条件判断等,但是可以非常直观的表示出参与者之间的调用关系,以及哪个参与者正在执行哪个处理过程。
二、Centralized control
Centralized control 由一个参与者负责所有的处理流程,其它参与者提供数据。
下面的实例是根据订单 Order计算总价格,需要先计算OrderLine中所有的Item的价格,然后计算总的折扣(overall
discount)。
每一个参与者都有一个垂直的 lifeline,应该从上往下的顺序阅读消息(Message)。
上图并不能表示出,getQuantity, getProduct, getPricingDetails,
and calculateBasePrice 需要对每一个 Order Line 进行计算,而 calculateDiscounts
仅仅需要计算一次。
UML 1中,所有的参与者(participants)都可以看作是一个对象实例,可以在名称下面加下划线来表示。
UML 2中,这些参与者的角色更加复杂,可以统称为 participants,不再加下划线表示。可以用
anOrder 这种方式表示,完整的方式是:name : Class。
每个 lifeline 上都有 activation bar,表明了参与者在交互中何时被激活,其实对应的是该参与者的某个方法。
activation bar 是可选的,但可以很清楚的解释交互动作,因此非常有用。唯一的例外是在开会讨论设计的时候,由于不方便画在白板上,才不使用。
名称可以很好的把参与者关联起来,例如 getProduct 方法返回的是 aProduct。
这里还使用了一个返回箭头来表示他们之间的关联。但是一般只用于返回时增加了信息的情况下。
第一个消息并没有发送它的参与者,这称为 found message。
三、Distributed control
Distributed control 将处理流程分散给了多个参与者,每个参与者都会负责完成一个小的逻辑。
与上面的方式不同,这里 Order 调用 每一个 Order Line 计算各自的价格,相应的会传递一些参数。然后调用
Customer 去计算折扣,相应的 Customer 会调用 Order 来获取一些数据。
推荐使用 Distributed control 方式,主要的优点是,可以把改动带来的作用限制到一个局部范围。数据以及相应的操作经常会变动,OO设计的一个原则就是,把数据和相应的操作放在一起。
其次,使用 Distributed control 方式可以更多的使用多态性,而不是使用条件判断。比如,product
的 price 计算方式变化了,我们就可以使用子类进行计算,来应对这种变化。
总之,OO设计的风格就是尽可能使对象细化,对象的方法细化,从而为我们提供了很多插入点,可以进行系统的重新设计和变动。
四、Creating and Deleting Participants
1、创建参与者
直接把消息箭头指向新创建的参与者的方框上面,这里名称是可选的,如果只是调用了构造函数,但推荐在任何情况下使用new。
如果新参与者在创建后立即就执行某些操作,则在方框正下方直接使用一个 activation bar 进行描述。
2、删除参与者
删除参与者使用一个大叉(X)来标记。
一个消息的箭头指向一个大叉,表示一个参与者明确的删除一个参与者。
一个 lifeline 结束位置的大叉,表示一个参与者删除自己。
在垃圾自动回收的环境中,我们一般并不直接去删除一个对象,但是还是应该使用大叉指出该对象已经不再需要并准备好进行回收了。同样适用于关闭(Close)操作,表明该对象不再可用。
五、Loops, Conditionals, and the Like
一个难题是,如何使用 sequence diagrams 来描述循环和条件判断。应该指出,sequence
diagrams 只是适合描述对象之间的交互,而不应该用于控制逻辑的建模(而是应该使用 activity
diagram 甚至直接使用代码实现)。
1、Interaction frames
这是UML 2里新增加的。
可以使用 interaction frames 来描述循环和条件判断。interaction frames
把 sequence diagram 划分成许多部分。
procedure dispatch
foreach (lineitem)
if (product.value > $10K)
careful.dispatch
else
regular.dispatch
end if
end for
if (needsConfirmation) messenger.confirm
end procedure
frames 由一些 sequence diagram 区域(region)组成(region由sequence
diagram 片断组成)。每一个 frame 都有一个操作符(operator),每一个片断都有一个条件(guard)。
对于循环,操作符是loop,只有一个片断,条件是迭代所有的成员。
对于条件判断,操作符是alt,两个片断各有一个条件,只有条件为真的片断才执行。
如果只有一个区域,操作符是opt
2、Older conventions for control logic
UML 1 使用 iteration markers and guards,iteration marker
是给message名称上面添加*,可以在方括号里注明迭代条件,guards是在方括号里注明条件,只有为真,才发送该message。
3、Common Operators for Interaction Frames
Operator |
Meaning |
alt |
Alternative multiple fragments; only the one
whose condition is true will execute. |
opt |
Optional; the fragment executes only if the
supplied condition is true. Equivalent to an alt
with only one trace. |
par |
Parallel; each fragment is run in parallel. |
loop |
Loop; the
fragment may execute multiple times, and the guard
indicates the basis of iteration. |
region |
Critical region; the fragment can have only
one thread executing it at once. |
neg |
Negative; the fragment shows an invalid interaction. |
ref |
Reference; refers to an interaction defined
on another diagram. The frame is drawn to cover
the lifelines involved in the interaction. You
can define parameters and a return value. |
sd |
Sequence diagram; used to surround an entire
sequence diagram, if you wish. |
4、问题
1)Iteration markers and guards 可以解决一些问题,但是也有弱点。如不能表明一组条件是互斥的;在一个循环或者条件处理中,只能是单独的一个message,如果一个activation发出多个message,就有问题。
对后面的问题可以使用 pseudomessage 解决。with the loop condition
or the guard on a variation of the self-call notation。使用没有箭头的消息,表明这不是实际上的调用。也可以给activation
bar加灰色阴影。也可以用自定义的方式。
2)活动图(activations)对 dispatch 方法并不有效,比如,发出一个message,但是接收器却没有任何其他动作。所以,一般这种调用就不画出了。
3)Parameters的表示
没有专用的符号,可以使用 message name 和 返回箭头来表示。在 method 的周围使用
Data tadpoles 来表明数据的移动方向。
4)一般推荐使用 pseudomessages, 而不是 interaction frames。
六、Synchronous and Asynchronous Calls
UML 2中使用实心箭头(filled arrowheads)表示synchronous message,尖箭头(stick
arrowheads)表示 asynchronous message。
这与 UML1.4 不兼容,在 UML 1.4中,使用 half-stick arrowhead 表示
asynchronous message。
推荐使用 half-stick arrowhead 表示 asynchronous message。
一般可以推断是 synchrony,除非明确表明区别。
七、When to Use Sequence Diagrams
Sequence Diagrams 应该用于在一个 Use case 图中观察几个对象之间的交互关系,可以很好的描述它们之间的协作。但是不适用于描述精确的行为。
如果需要在多个 Use case 中描述一个对象的活动,应该使用 state diagram。
如果需要在多个 Use case 或者 多个 threads 中描述活动,应该使用 activity diagram。
八、CRC Cards
如果需要比较几个备选的交互方案,最好使用 CRC cards,可以避免反复的绘制和删除。CRC cards
很容易使用,然后使用 sequence diagrams 来描述选择的那个。
一个有用的技巧是,研究对象的交互,关注行为而不是数据,这可以帮助设计一个好的OO 方案。
CRC (Class-Responsibility-Collaboration) diagrams 由
Ward Cunningham 在 1980’s 提出,UML并没有包含,但是很多有经验的设计人员却经常使用。
一个实例:
To use CRC cards, you and your colleagues gather around
a table. Take various scenarios and act them out with
the cards, picking them up in the air when they are
active and moving them to suggest how they send messages
to each other and pass them around.
This technique is almost impossible to describe in a
book yet is easily demonstrated; the best way to learn
it is to have someone who has done it show it to you.
An important part of CRC thinking is identifying responsibilities.
A responsibility is a short sentence that summarizes
something that an object should do: an action the object
performs, some knowledge the object maintains, or some
important decisions the object makes. The idea is that
you should be able to take any class and summarize it
with a handful of responsibilities. Doing that can help
you think more clearly about the design of your classes.
The second C refers to collaborators: the other classes
that this class needs to work with. This gives you some
idea of the links between classes—still at a high level.
One of the chief benefits of CRC cards is that they
encourage animated discussion among the developers.
When you are working through a use case to see how classes
will implement it, the interaction diagrams in this
chapter can be slow to draw. Usually, you need to consider
alternatives; with diagrams, the alternatives can take
too long to draw and rub out. With CRC cards, you model
the interaction by picking up the cards and moving them
around. This allows you to quickly consider alternatives.
As you do this, you form ideas about responsibilities
and write them on the cards.
Thinking about responsibilities is important, because
it gets you away from the notion of classes as dumb
data holders and eases the team members toward understanding
the higher-level behavior of each class. A responsibility
may correspond to an operation, to an attribute, or,
more likely, to an undetermined clump of attributes
and operations.
A common mistake I see people make is generating long
lists of low-level responsibilities.
But doing so misses the point. The responsibilities
should easily fit on one card. Ask yourself whether
the class should be split or whether the responsibilities
would be better stated by rolling them up into higher-level
statements.
Many people stress the importance of role playing, whereby
each person on the team plays the role of one or more
classes. I've never seen Ward Cunningham do that, and
I find that role playing gets in the way.
Books have been written on CRC, but I've found that
they never really get to the heart of the technique.
The original paper on CRC, written with Kent Beck, is
[Beck and Cunningham]. To learn more about both CRC
cards and responsibilities in design, take a look at
[Wirfs-Brock].
九、Other interaction diagrams
比较有用的交互图如:
communication diagrams, 用于描述连接。
timing diagrams,用于描述时间约束。
|