一、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,用于描述时间约束。 |