三 用例实现
目前我们已经把握了重点用例,现在则要“实现”用例。用例的实现指的是对每个用例所进行的详细系统过程的说明,在这个过程中,我们以UML的方法给出了类图设计、顺序图、状态图,甚至包括UI设计和E-R设计等等,目的是为系统进一步的详细设计提供概念上的依据和设计参照。
1 “创建订单”用例
图1: Stamp DIY Physical Object Model
图1中的业务关系类图,我们有如下描述:
a. 订单Order和订单行OrderDetail是组合关系。订单Order和OrderDetail构成上下级别的一对多关系,它们拥有着一致的生命周期。
b. 产品目录Catalog和目录项Catalogitem也是组合关系,拥有一致的生命周期。
c. 客户Customer和Order 形成关联类,二者构成强制关系, 即客户类Customer不存在的情况下,订单类Order是不存在的。
d. 客户Customer从本质上是一种角色Role,所以客户Customer可以视为Role角色的子类,Customer继承了Role的属性。
我们在设计域类通常会遵循一些基本的设计准则,如下:
封装——封装是一种设计准则,规定了数据和程序逻辑包含在一个独立的单元中。
导航可见性——是一种设计准则,指一个对象可以看到另一个对象并与之交互。
设计的任务之一是说明哪个对象对哪个对象有导航可见性,它可以是单向或双向的。如图1,一个Customer对象可以看见一个Order对象,它意味着Customer对象可以知道客户发出了哪些订单。在程序里,Customer类通常会用一个变量或数组来指向这个客户的一个或多个Order对象。在设计类图中,导航可见性用类之间的箭头表示,箭头指向可见的类。
耦合——它来自于导航可见性,如图一,Customer对Order是可见性的,则它们是耦合的,同样,Order对OrderDetail也具导航可见性,它们也是耦合的。
耦合是对设计类图中的类与类之间连接关系的紧密程度的定性的度量。一种比较容易理解耦合的方法是看设计了类图的导航箭头的个数,比如Customer对Order是耦合的,Order对OrderDetail是耦合的,这些是正常的设计。但如果把Customer加入到对OrderDetail的导航可见性则是强耦合的类型,这样的设计会降低系统的维护性。
通常,有经验的分析员会尽量简化耦合,并减低对新系统设计的影响。
聚合与任务分解——指的是一个类中各种功能的一致性,它是对一个类中目的单元或主题的定性度量。
我们需要的是高聚合的类设计, 因为低聚合的类不容易维护,重用度低。在图1中,我们把客户,订单和购物车分解成几个高聚合的类.为解决低聚合的类通常采用的分成几个高聚合类的方法是为任务分解,它是另一个面向对象设计的准则。
图2: DB Schema
如图2的数据E-R设计,我们可以得出如下描述:
键是E-R设计的重要角色,主键惟一地表示了数据模型内一个实体的各实例,而通过外键则把各实体连接在一起。
在图2中,Order表的主键是OrderID,它是自增型整数序列ID,它的外键是CustomerID,映射到了Customer表;而OrderDetail表的主键则是通过组合键(Composite Key)的OrderID和DetailLineID来定义的;而Categories表的主键是GUID,一种唯一性的全球标识码。
从图2中,我们已经看到了数据表的定义主键的几种基本方法。
图3: “创建订单”顺序图
对于图2的“创建订单”顺序图 ,我们有如下描述。
开发交互图是面向对象设计的核心,实现用例的过程就是通过确定哪些类通过发送消息与其他类交互协作的过程,顺序图是交互图的一种。顺序图用于描述进出自动系统的信息流,一个系统顺序流记录了输入和输出并且标识了参与者和系统之间的交互。在图3中,已经形象地描述了参与者如何通过数据和获得输出数据来和系统进行交互地。
图3中,由下划线对象和一个矩形框组成的是整个系统的各个对象,按照对象出场先后顺序排列,它们是Customer、Website、Account、Product、Order、Order LineItem、Authoriy。
一旦对象已经确定,我们需要给出的是贯穿每个对象生命周期和连接各个对象交互的消息,对于每一条消息,我们有必要列出消息源对象和目的对象。如图3所示,Customer作为系统参与者,先后给WebSite、Account、Order等对象发送了消息,而各个对象也各参与者的Customer返回了消息,这样地消息循环最终完成了用例所描述的流程。
比如Customer在本用例中先后发送了如下消息完成了与系统的整体交互过程:
- Browses To : 原始消息,从Customer到Web Site,Web Site返回了消息“ Request Credentials” 。
- Provide Credentials: 从Customer到Web Site,Web Site返回了消息“ Display homepage” 。
- Create Orders: 从Customer到Order。
- Find Product : 从Customer到Product.的内部消息开始,引发了从Product到Order的系统主要消息“Add Product to Order”,接着通过发送源于Order的“Add Order Item:”这一消息的发送到Order Line Item更显顺理成章,从而完成了用例基本流程的第4步。
- Modify Quantity : 从Customer到Product 。
- Enter Payment Info:从Customer到Order。
- Submit Order:到此Customer已经完成了最后一个消息的发送, 通过本顺序图的完成也以黑匣子的角度模拟了系统的流程。
现在让我们探讨顺序图的设计规则:
a) 接受每个输入消息并确定由这个输入消息产生的所有内部消息。
确定消息的目标。需要什么消息,哪个类(即目的地)需要这条消息,以及哪个类(即消息源)提供这条消息。这种分析有助于理清内部消息、源对象和目的地对象。
b) 在处理每个消息的时候,要辨别出受之影响的类的完整集合,即从域类图中找到需要的所有对象。在用例的前提条件和后续条件中罗列的任何类都应该包含到设计中去,即被创建的类、创建用例对象的类、用例期间更新的类,以及提供用例需要信息的类。
c) 充实消息的结构,添加迭代、正/误条件、返回值和传递参数。传递参数应该参考域类的属性。返回值和传递参数可以是属性,也可以是类中的对象。
本文行文至此,基本完成了用例“创建订单”的实现,同时探讨了交互设计应当遵循的准则,希望给读者有所参考和帮助。