Lab 1: 应用程序建模
实验目标
这个实验的目的是展示如何在Visual Studio 2010旗舰版中进行应用程序建模。团队中的架构师会通过建模确定应用程序是否满足客户的需求。 你可以创建不同级别的详细模型,并将它们彼此结合、测试然后发布到你的开发计划里。
在这个实验中, 我们将重点放在如何创建一系列简单的系统建模图形上.
每个练习应该在 30分钟内完成.
Exercise 1 – 理解用户需求
绘制活动、类以及其他UML图形能帮助架构师清晰辨别客户的习惯、业务规则以及其他需求,从而使设计与客户需求保持一致。
微软Visual Studio 2010旗舰版可以让你绘制关于客户的活动以及你的系统如何帮助客户达到他们的预期,这样有助于你理解用户需求,并能够与客户进行良好的沟通和讨论。
需求模型可以帮助你:
l 专注于系统的外部行为,并与系统内部设计分离。
l 使用比自然语言更少的更精准的方法描述客户以及投资者的需求。
l 定义一个可以由客户、开发人员以及测试人员一致使用的术语词汇。
l 减少需求中的差距和分歧。
l 降低针对需求变化的响应所付出的工作量。
l 规划哪些功能需要开发。
l 使用模型作为系统测试的基础,使其成为客户需求与测试人员之间的纽带。当需求变更时,这种纽带可以帮助你迅速更新测试。这样可以使系统尽快满足新的需求。
如果你将重点放在每次迭代开始时与客户的讨论上,那么需求模型会给你提供很大的便利。而且你不能在完成设计之前编写详细代码。部分应用程序功能,即使它非常简单,通常也是构成与用户讨论时最敏感的需求基础。模型可以有效地总结讨论结果。
Task 1 –用户需求建模——用例图
创建用例图来描述谁使用该系统,以及他们如何使用。用例图代表一个系统用户的目标,以及他们执行程序的流程。
这个任务中,客户需要一个在线餐饮销售系统。该系统必须允许客户从菜单中选择食品,而且必须提供销售商更新食品品种的菜单。你可以使用以下步骤实现该用例图:
1. 启动 Microsoft Visual Studio 2010.
2. 选择 文件->新建->项目,如下所示:.
Figure 1: 打开新建项目对话框
3. 在新建项目对话框中, 选择项目类型下的建模项目,然后在右侧项目模板中选择建模项目.
修改项目名称为ModelingProjectDinnerNow. 保持默认项目路径.
Figure 2: 创建新建模项目
Figure 3: 空的建模项目
5. 在解决方案浏览器中右键单击ModelingProjectDinnerNow项目根节点,在弹出菜单中选择添加->添加新项
Figure 4: 添加新项菜单
6. 在弹出的添加新项对话框中,选择UML用例图模板,并修改用例图的名称为UMLUseCaseDiagramDinnerNow.usecasediagram
Figure 5: 添加新项对话框
7. 单击添加,此时会打开空白用例图
Figure 6: 空白用例图UMLUseCaseDiagramDinnerNow.usecasediagram
8. 根据案例用户需求,从左侧工具箱中的UML用例图节点下拖拽两个用例图标到右侧设计界面。
Figure 7: 从工具箱中拖拽两个用例图标
9. 点选用例图标的”UseCase1”文字部分,使其变为可编辑状态,然后将其内容修改为Order a Meal
10. 重复步骤9的操作,将用例2的用例内容修改为Update Menu。
Figure 8: 用例定义修改后的效果
11. 根据案例用户需求,从左侧工具箱中的UML用例图节点下拖拽两个活动者图标到右侧用例图设计界面
Figure 9: 从工具箱中添加活动者
12. 点选用活动者图标的”Actor1”文字部分,使其变为可编辑状态,然后将其内容修改为Customer
13. 重复步骤12的操作,将活动者2的定义修改为Restaurant
Figure 10: 定义活动者后的效果
14. 在工具箱中选中Association图标,然后在设计界面中首先点选Customer图标,并保持鼠标按下,拖拽到Order a Meal用例上。
Figure 11: 选择Association图标后的效果
Figure 12: 拖拽过程中的效果
Figure 13: 拖拽完成的效果
15. 按照步骤14的方法,为Restaurant活动者与Update Menu用例建立联系
Figure 14: 用例图初步完成效果
16. 还可以生成更精确的用例图。例如,订餐只是购买活动的一个步骤。整个购买活动应该还包含付款和交货等。
17. 在工具箱中选择子系统图标,并将其拖拽到设计界面中,放置于前一步骤中完成的用例图的下方
Figure 15: 添加子系统图标
18. 点选子系统图标中左上角的“SubSystem1”文字,使其可以编辑。将“SubSystem1”文本修改为“Dinner Now System”
Figure 16: 修改子系统名称
19. 选中上面我们定义的两个用例:Order a Meal、Update Menu。将其拖拽到子系统图标内,并调整相互位置。
Figure 17: 将用例拖拽到子系统内
Figure 18: 目前为止完成的更精确的用例图
20. 从工具箱中拖拽两次用例图标到子系统图标内,分别定义为Buy a Meal、Pay for Meal
Figure 19: 添加子系统内部用例后的效果
21. 由于订餐和付款共同属于购买行为的组成部分,所以Order a Meal、Pay for Meal都包含在Buy a Meal中。需要在工具箱中选中包含图标,分别在Buy a Meal 与 Order a Meal ;Buy a Meal 与Pay for Meal之间建立包含关系。
Figure 20: 建立Buy a Meal包含关系后的效果
22. 由于Buy a Meal 作为客户使用的总用例,所以这里删除Customer活动者与Order a Meal用例的联系,建立Customer活动者与Buy a Meal用例的联系。调整用例之间的位置。
Figure 21: 修改Customer活动者关系后的效果
23. 由于送餐并不属于Dinner Now System的功能,可能会有专门的物流或快递系统负责,这里,将送餐定义在Dinner Now System系统的外部。在Dinner Now System子系统图标外部添加一个新的用例,定义为Deliver Meal。并指定它与Restaurant活动者之间的联系。
Figure 22: 添加送餐用例后的效果
24. 送餐用例虽不属于Dinner Now System系统的功能,但是也是购买行为的组成部分,这里需要建立Buy a Meal用例与Deliver Meal用例之间的包含关系
Figure 23: 最终用例图完成的效果
25. 到此用例图设计完成,保存并关闭当前设计界面。
你还可以定义哪些用例包含在你系统的开发范围之内。例如,我们案例中的Deliver Meal用例就不需要开发。这就帮助开发人员界定了他们的工作内容。一般用例图中的子系统图标用来代表系统或组成部份。
用例图还可以帮助你的团队讨论功能发布的连续性。如,你可以决定是否在最初的版本中包括付费功能,或者可以不包含。如果系统中不包含付费功能,那么也可以由客户在餐厅直接支付,而不经过系统。这样,你就可能不在你的系统最初版本中包含付费功能。
用例图只是一个总体的描述,而要想得到更详细的用例描述,你可以将你的用例图中的每个用例都导航到一个用例文档中。用详细的用例文档来描述用例。
Task 2 – 概念类图
你可以使用UML 类图来开发用于下列用途的概念模型:
l 客户可以自己参与到系统的开发过程中
l 描述用户的需求,例如,在描述用例、业务规则以及用户使用习惯方面。
l 系统中的API或用户界面的信息类型变更
l 描述系统或验收测试
出于这样的目的,UML类图的概念就被定义为概念类图。
在一个概念类图中,你只需要展示必要的需求描述,而不需要展示系统内部的设计。概念模型中不应该出现操作或接口。
你可以使用如下步骤定义概念模型:
1. 在解决方案浏览器中右键单击ModelingProjectDinnerNow项目根节点,在菜单中选择添加->添加新项
Figure 24: 添加新项对话框中选择UML类图
2. 在添加新项对话框中选择UML类图模板,并定义名称为UMLClassDiagramDinnerNow.classdiagram. 效果如上图所示。
3. 点击添加按钮,打开空白UML类图设计界面.
Figure 25: 空白UML类图设计界面
4. 在Task 1中我们设计到了两个对象:订单、菜单。根据经验我们知道,订单和菜单分别都要有各自的小项,即订单小项、菜单小项。所以我们首先从工具箱中拖拽四个类图标到设计界面,分别定义为Menu、MenuItem、Order、OrderItem。
Figure 26: 建立四个对象
5. 由于菜单和菜单小项、订单与订单小项是1对多的包含关系,所以我们需要在Menu与MenuItem、Order与OrderItem之间建立“构成”关系.从工具箱中选中Composition图标,然后点选Menu对象。保持鼠标按下状态,拖拽到MenuItem对象上,生成Menu与MenuItem对象之间“构成”关系
Figure 27: 拖拽关系
Figure 28: 建立Menu与MenuItem的构成关系
6. 由于Menu与MenuItem是1对多的包含关系,所以,选中设计界面中在上一步骤生成的Composition图标,点选右侧下方的1文本,使其可以编辑。将其更改为*。选中左侧下方的MenuItem文本,将其修改为Contents
Figure 29: Menu对象与MenuItem对象之间的Composition关系
7. 重复5、6步骤,设置Order对象与OrderItem对象之间的Composition关系
Figure 30: Order对象与OrderItem对象之间的Composition关系
8. Menu对象与Order对象之间存在1对多的联系,同样,MenuItem与OrderItem之间也存在着1对多的联系。所以,重复5、6步,在Menu与Order之间和MenuItem与OrderItem之间分别建立Association关系
Figure 31: 建立Association关系
9. 由于MenuItem和OrderItem在数据上有一个明显的不同就是,OrderItem必须包含数量,而MenuItem不需要包含。所以我们要在OrderItem中定义一个数量属性。在OrderItem对象中的属性一栏上点击右键,在弹出的菜单中选择添加->属性
Figure 32: 为OrderItem对象添加属性
10. 此时OrderItem对象中出现可编辑的属性,其文本为Attribute1。将Attribute1文本修改为quantity,然后右键选择quantity属性,在属性选项卡中修改属性的数据类型为Integer
Figure 33: 定义quantity属性
11. 至此 ,我们完成了概念模型的设计。保存并关闭当前概念类模型设计界面
Figure 34: 初步完成概念模型设计
概念模型提供了一系列你在整个需求建模阶段需要使用的词汇和条件。例如,在Order a Meal用例的详细描述中,可以这样写:
客户可以选择菜单来生成订单。通过在菜单中选择一个菜单项,系统在订单中生成订单项。
注意,上面描述中使用的词汇就是我们在模型中使用的类名。现在删除概念模型中类与类之间的不准确的关系。例如,图中明确显示了每个订单只关联一个菜单。
对客户需求的误解可以追溯到对词汇详细解释的误解。例如,大多数餐馆都有约定俗成的菜单和订单,但是订单项与菜单项的不同却区分并不明显。当与客户讨论需求时,暴露这些分歧是很重要的。类图是一个很有用的工具,它可以帮助你明确对象以及对象之间的关系。
业务规则是一个不与特定用例相关的需求,应该是从整个系统层面考虑。
许多业务规则是对概念模型中类之间关系的约束。你可以为概念类图中的相关类,定义一些通用静态业务规则。例如:
在概念模型中右键单击Order对象,在菜单中选择添加->添加注释添加如下约束:“在任何订单中,所有的订单项只能来自于同一个选中的菜单”
Figure 35: 对概念模型添加约束注释
动态业务规则限制的是事件发生的顺序。例如,你可以使用一个顺序或活动图来展示:一个用户必须登录才能执行你的系统上的操作。
因此,许多动态规则能够取代动态规则更有效更通用的执行约束。例如,你也许能添加一个布尔类型的属性“Logged In”到概念类模型中。你还会将登录成功作为登录用例的后置条件,还可以将登录成功作为其它用例的前置条件。这种方法可以让你定义一系列事件的组成顺序。当你需要添加新的用例到用例模型时,动态约束更加灵活。
Task 3 – 活动图
你可以使用活动图来显示不同用例之间的工作流程。在需求建模的开始阶段绘制活动图是非常有用的。它可以展示用户执行的主要任务——包含系统内外的交互。
这里以订餐为例:客户订餐时首先需要选择一个菜单,然后在菜单中选择某样菜品。客户可以在某个菜单内部重复多次的选择相同或不同的菜品。当菜品选择完毕后,客户可以将选中的菜品一并结账付款。
1. 在解决方案浏览器中右键单击ModelingProjectDinnerNow项目根节点,在菜单中选择添加->添加新项.
2. 在添加新项对话框中选择UML活动图模板,并定义名称为UMLActivityDiagramDinnerNow.activitydiagram. 效果如上图示.
Figure 36: 添加新项->UML活动图
3. 此时会打开活动图设计界面。点选设计界面的空白处,在属性选项卡中修改活动图的名称属性为Order Meal.此时活动图左上角的标签应该变为act Order Meal
Figure 37: 修改活动图的名称属性
4. 任何活动都从一个初始化节点开始的,所以从工具箱中的UML 活动图节点下选择初始节点图标,并拖拽到设计界面中.
Figure 38: 拖拽初始节点图标
5. 根据案例的描述,订餐活动中应该有选择菜单、选择菜品、付款三项主要活动。这里从工具箱中拖拽三个活动图标到设计界面,分别定义活动内容为“Choose Menu”、“Select Menu Item”、“Pay”.
Figure 39: 定义活动
6. 活动图定义的结尾,应该是活动的结束节点。从工具箱中拖拽活动结束节点到设计界面
Figure 40: 定义活动结束
7. 在工具箱中选中连接器图标,在设计界面点选初始图标并保持鼠标按下,拖拽到右侧Choose Menu活动图标上。
Figure 41: 拖拽活动之间的连接器
Figure 42: 定义第一个连接器后的效果
8. 根据任务中需求的描述,客户选择菜单后,可以再浏览选择菜品,即菜单项。而且客户可以反复浏览菜单和菜品。这样在选择菜品和选择菜单两个活动之间就形成了循环的关系。所以我们需要在Choose Menu活动的下方放置一个合并节点,然后在Select Menu Item活动的下方放置一个分支节点
Figure 43: 添加合并节点和分支节点
9. 从Choose Menu活动开始,以此向下添加连接器,直到Pay活动
Figure 44: 添加正常流程连接器
10. 为了说明客户可以在菜单中反复选择菜品,我们需要从分支节点到合并节点添加一个连接器,用来表示循环,并对循环活动添加注释。在分支节点的指向下方活动的连接器的Guard属性中添加如下提示:Customer has finished choosing.在返回上方的连接器的Guard属性中添加如下提示:Customer wants to choose more.
Figure 45: 添加循环活动
11. 当客户选择完所须的菜品后,任务就完结。这里我们从Pay活动到活动结束节点添加连接器。
Figure 46: 订餐活动终结
12. 至此,订餐功能的活动图我们就构建完成。
你可以利用用例图和活动图来展示针对相同信息的不同观点。用例图可以有效地显示在大的功能中的嵌套的小的活动,但它不包含活动之间的流程。
例如,同样是描述订餐功能,使用用例图描述如下
Figure 47: 用例图中的订餐活动
Task 4 – 顺序图
你可以使用顺序图来显示你的系统与外部活动者之间,或者系统与系统之间的信息交互。顺序图提供了一种用例,它可以非常清晰地展示系统模块之间的互操作步骤。顺序图在描述多个用例之间的交互时非常有效,而且为你的系统提供一些API。
1. 在解决方案浏览器中右键单击ModelingProjectDinnerNow项目根节点,在菜单中选择添加->添加新项.
2. 在添加新项对话框中选择UML顺序图模板,并定义名称为UMLSequenceDiagramDinnerNow.sequencediagram.
Figure 48 新建UML 顺序图界面
3. Dinner Now系统中的功能主要是四个对象之间的交互,他们是客户、Dinner Now 系统、餐厅、银行。打开UML模型浏览器,可以看到已经包含客户活动者、Dinner Now子系统以及餐厅活动者,所以可以直接拖拽这三个用例到顺序图设计界面
Figure 49 添加客户、DinnerNow子系统、餐厅三个生命线
4. 由于我们之前设计的用例中暂时不包含银行用例,所以我们需要从工具箱中拖拽一个生命线图标到设计界面,并在空生命线的属性面板中修改名称属性为Bank,修改Type属性为None。
Figure 50 从工具箱中拖拽生命线图标到设计界面
Figure 51 修改Bank生命线属性
5. 根据需求我们知道客户需要在菜单中不断的浏览,不断的选择,系统也是不断的将客户选中的菜品添加到订单中。所以我们首先在Dinner Now System生命线上添加一个异步的调用。首先在工具箱中选中异步图标,然后在设计界面上选中客户生命线,保持鼠标按下,拖拽到Dinner Now System生命线上
Figure 52 拖拽异步图标从Customer生命线到Dinner Now System生命线
Figure 53 建立异步调用后的效果
6. 单击Message1文本,使其可编辑,将Message1文本修改为 Add Order Item
Figure 54 修改调用的名称
7. 因为客户挑选菜品的过程是一个循环往复的过程,所以需要标注循环。右键单击Add Order Item调用,在弹出的菜单中选择包围->循环组件片段。
Figure 55 添加循环组件片段菜单
Figure 56 添加循环片段的效果
8. 在循环片段左上角的Loop文本下方单击空白区域,出现可编辑文本框,定义文本内容为until complete
Figure 57 编辑循环标签
9. 当客户选择完菜品后,需要最终确认并提交订单。重复步骤5、6,从客户生命线到Dinner Now 系统生命线建立异步调用,并修改调用名称为Confirm Order
Figure 58 添加Confirm Order异步调用
10. 客户确认订单后,系统会将订单发送给餐厅等待处理,此时,餐厅需要通过系统反馈给客户一个订单发送是否成功的确认。我们需要从工具箱中拖拽一个同步调用。在设计界面中,从Dinner Now系统生命线上生成的矩形图标,拖拽到右侧的餐厅生命线上
Figure 59 在Confirm Order调用与餐厅生命线之间建立同步调用
11. 将指向右侧的调用文本Message1,修改为Send Order。将下方指向左侧的回调文本return,修改为OK
Figure 60 修改回调方法名称
12. 系统收到餐厅的确认后,客户就可以付款了。系统会请求客户提交付款的详细信息。付款成功的信息会直接返回给客户。重复步骤10、11,从客户生命线 到Dinner Now 系统生命线之间建立同步调用,将指向右侧的调用名称修改为Payment detail,将指向左侧的消息回调名称修改为confirmed
Figure 61 添加付款功能调用和确认
13. 客户提交付款详细信息后,系统会直接与银行之间执行付款操作流程。而系统与银行之间的付款流程完成后,银行也会返回给Dinner Now 系统一个确认信息。所以重复步骤10、11,从Dinner Now系统上的Payment detail调用矩形图标,到银行生命线建立同步调用。将指向右侧的调用名称修改为Process Payment,将指向左侧的回发调用名称修改为OK
Figure 62 添加执行付款调用和确认
14. Dinner Now系统收到银行的付款确认后,会将确认信息和最终订单发送给餐厅。而餐厅收到订单这个调用应该先于系统给客户的确认。所以我们需要在Dinner Now系统生命线中的Payment detail调用矩形图标上,在银行反馈给系统付款确认信息之后,建立一个到餐厅生命线的异步调用。并将异步调用的名字改为Confirm Order
Figure 63 添加确认订单调用
15. 当Dinner Now系统向客户返回了订餐成功的最终确认后,餐厅就可以为客户送餐了。而送餐的动作不需要经过Dinner Now系统,所以,在Payment detail 调用结束后,直接从餐厅生命线上的Confirm Order调用上,向客户生命线添加一个返回的异步调用Deliver Food。且confirmed回发,和Deliver Food调用应该是并行的 。
Figure 64 添加送餐调用
总结
创建模型往往可以大幅减少需求分析中与客户的需求相矛盾或含糊不清的地方。不同的利益相关者往往对系统运行的业务流程有不同的理解。因此你的第一个任务就是解决这些你和客户之间的分歧。
你会发现 ,
Exercise 2 – 软件设计建模
图形建模可以帮助你了解、澄清你的系统必须实现的客户需求,并使你的代码能够与客户进行良好的意见沟通。例如,你可以使用统一建模语言(UML)的用例图、活动图、类图以及顺序图来描述用户需求。你可以使用UML的组件图、类图、活动图、顺序图来描绘系统的功能。
Task 1 – 活动图
这个案例中我们需要参考在需求分析建模中构建的活动图UMLActivityDiagramDinnerNow.activitydiagram。但是在软件设计阶段和需求分析阶段的活动图略有不同,例如UMLActivityDiagramDinnerNow.activitydiagram中的Pay活动其实并不经过Dinner Now系统,所以我们需要对需求分析建模中的Pay活动进行修改。将其换成一个行为调用活动,并命名为Confirm Order
Figure 65 修改调用活动
通过需求分析建模中用例图和活动图的描述,我们得知,创建订单时,配货与付款是并发的两件事。所以我们需要在软件设计建模中的活动途中对其加以细化。
1. 在解决方案浏览器中右键单击ModelingProjectDinnerNow项目根节点,在菜单中选择添加->添加新项
2. 在添加新项对话框中选择UML活动图模板,并定义名称为UMLActivityDiagramCreateOrder.activitydiagram.
Figure 66 新建创建订单活动图
3. 从工具箱中拖拽活动的起点图标到设计界面,命名为InitialCreateOrder,然后再拖拽第一个活动到设计界面,命名为Create Order
Figure 67 创建订单活动图的起始阶段
4. 从工具箱中拖拽一个并行分支节点到设计界面并命名为ForkCreateOrder,以此来表示任何进入这里的处理流程都会被分解为若干个并行的处理进程。然后添加从Create Order活动到并行分支节点的连接器。
Figure 68 添加并行分支节点
5. 在并行分支节点的右侧,首先建立配货活动的进程。从工具箱中拖拽一个活动到设计界面中,放置在并行分支节点的下方偏右侧区域,命名为Dispatch goods。建立分支节点指向Dispatch goods活动的连接器。
Figure 69 添加配货活动
6. 在并行分支节点的左侧,建立与配货进程并行的付款进程。通过需求分析建模中顺序图的描述,我们 了解到,付款行为并不真正由系统完成,而是客户首先出发系统的付款事件,然后系统会直接将事件请求发送到银行,并同样利用事件机制监听银行端发回的付款确认。由此我们需要两个新的活动。一个是用来发送请求的事件活动,一个是用来接收回发的事件活动。因此,从工具箱中首先拖拽一个发送请求活动到设计界面中并行分支活动的左侧,命名为Send invoice。并建立从并行分支活动到Send invoice活动的连接器。
Figure 70 添加与配货活动并行的发送请求活动
7. 在发送请求Send invoice活动的下方,再从工具箱中拖拽一个接收事件活动,命名为Receive payment。建立从Send invoice活动到Receive payment活动的连接器。
Figure 71 添加接收付款确认事件
8. 两个并行处理进程定义好之后,需要最终汇集到主要处理流程上继续执行,所以需要从工具箱中拖拽一个并行汇总图标到设计界面的下方,命名为JoinCreateOrder。分别从Receive payment活动和Dispatch goods活动向并行汇总图标建立连接器
Figure 72 添加并行汇总节点
9. 最后是关闭订单,也代表着订单处理成功。所以需要从工具箱中拖拽一个活动到设计界面的下方,命名为Close Order。在Close Order活动的下方再放置一个活动终结图标。分别从上到下建立连接线。
Figure 73 完成创建订单活动图
到此创建订单的活动就完成了。保存并关闭当前设计界面。
Task 2 – 数据流图
你还可以使用数据流图来描述数据从一个动作流向另一个动作。这个任务中,我们模拟订单生成过程中数据的流向及其对存储介质以及活动的影响。在生成订单过程中,订单小项和客户地址分别会有不同的数据流向,也会影响不同的活动,所以我们以订单中的这两部分数据作为任务的开始。
1. 在解决方案浏览器中右键单击ModelingProjectDinnerNow项目根节点,在菜单中选择添加->添加新项
2. 在添加新项对话框中选择UML活动图模板,并定义名称为UMLActivityDiagramOrderDataflows.activitydiagram.
3. 从工具箱中拖拽两个活动参数图标到设计界面,水平并排放置,通过单击图标上的文本,使其可编辑。分别命名为Item list和Customer Address。
4. 订单生成的过程首先会按照当前订单中的商品列表,在商品库存中找到相应的商品。所以需要从工具箱中拖拽一个活动到设计界面中,Item list的下方。命名为Find goods in warehouse。
Figure 74 添加查找库存货物活动
5. 由于Item list是以参数的形式进入Find goods in warehouse活动的。所以我们需要给Find goods in warehouse活动定义输入接口。右键单击Find goods in warehouse活动,在右键菜单中选择添加->Input pin。通过单击接口上的文本Input1,使其可编辑,并将文本定义为Item list。然后从Item list参数图标,到新建的输入接口添加连接器。
Figure 75 添加输入参数接口的右键菜单
Figure 76 为Find goods in warehouse活动添加输入参数Item list
6. 客户的地址需要生成为派送货物时的地址标签。所以Customer Address应该是Print address label活动的输入参数。所以,重复步骤4、5。添加Print address label活动,并为其添加输入参数接口Customer Address。
Figure 77 添加Print address label活动,并定义它的Customer Address输入参数
7. 当系统在物品库存中找到了客户选择的物品后,会完成两个工作。一是把每个购买物品的数量从库存数量中减去。二是生成订单号,以便唯一记录或查阅订单。要完成第一个任务,我们需要定义一个对象,来保存需要修改的物品数量记录。所以,从工具箱中拖拽一个对象节点图标到设计界面中Find goods in warehouse活动的下方,单击文本Object1将其内容修改为Stock Update Record。由于不存在参数的关系,所以只需直接从Find goods in warehouse活动到Stock Update Record对象建立连接器。
Figure 78 添加Stock Update Record对象
8. 系统会使用专门的活动来将Stock Update Record对象中保留的数据,更新到实际的数据库中。从工具箱中拖拽一个活动到设计界面,放置在Stock Update Record对象的下方,并将其命名为Update stock database。并建立从Stock Update Record对象到Update stock database活动的连接器。(这里不使用参数的原因是由于Stock Update Record是对象,可以拥有并调用自己专属的方法,而不是将自己作为参数传递给别人的活动)
Figure 79 添加Update stock database活动
9. 步骤7中提到的第二件事就是生成订单号,而订单号会与打印的地址标签一同成为配送物品的重要依据。所以从工具箱中拖拽一个 新的活动,放置在Find goods in warehouse活动和Print address label活动的下方。将其命名为pack goods。
Figure 80 添加Pack goods活动
10. Pack goods活动需要的两个输入参数:订单号和地址标签,分别来自于Find goods in warehouse活动和Print address label活动。所以可以参照步骤4、5分别为Find goods in warehouse活动和Print address label活动添加输出参数接口,分别命名为Order Id和Address label。与之对应的,要在Pack goods活动上建立两个输入参数接口用来接收Order Id和Address label。最后,分别从Order Id输出参数接口和Address label接口,到Pack goods活动上各自给定的输入参数接口,建立连接器。
Figure 81 为Pack goods活动提供参数来源
11. 当Pack goods活动完成后,就可以发货给客户。此时在Pack goods活动下方简单添加一个活动,命名为Ship goods to customer。
Figure 82 添加送货活动
12. 到此,关于生成订单与送货的数据流程图就完成了,保存并关闭当前设计界面。
Task 3 – 组件图
在Visual Studio 旗舰版中,组件图展示的是软件系统设计的组成部分。组件图可以帮助你可视化的定义高层次的系统结构以及服务行为的接口与调用。这个任务中我们模拟客户使用Web浏览器与我们的Dinner Now系统完成订餐过程的组件间关系。
1. 在解决方案浏览器中右键单击ModelingProjectDinnerNow项目根节点,在菜单中选择添加->添加新项
2. 在添加新项对话框中选择UML组件图模板,并定义名称为UMLComponentDiagramDinnerNow.componentdiagram.点击添加,进入组件图设计界面。
Figure 83 新建组件图
3. 从工具箱中拖拽一个组件图标到设计界面,单击文本Component1,将其修改为Web Browser。单击Web Browser组件左上角的收放箭头,将其收缩。
Figure 84 添加Web Browser组件
4. 从工具箱中拖拽另一个组件图标到设计界面,单击Component1文本,将其修改为DinnerNow Web Service。调整其大小如下图所示
Figure 85 添加Web Browser组件
5. 在 DinnerNow Web Service组件中应该提供了餐厅所拥有的功能,如招待客户订餐的服务和进行餐饮烹饪的服务。所以,模仿步骤3,在DinnerNow Web Service组件中放置两个小的组件,分别命名为Customer Web Server和Kitchen Server。在属性选项卡中,修改名称属性为相应的名称。
Figure 86 在DinnerNow Web Server组件中添加Customer Web Server 组件和Kitchen Server 组件,并重命名
6. 客户通过浏览器请求访问到DinnerNow Web Service组件中的Customer Web Server组件,进行餐饮相关的检索和订餐。所以右键单击Web Browser组件,选择添加->请求接口。
Figure 87 添加请求接口菜单项
7. 由于浏览器请求DinnerNow Web Service使用HTTP协议,单击请求接口的文本Interface1,修改为HTTP,并在属性选项卡中将HTTP请求接口名称Port1修改为HTTP。
Figure 88 添加HTTP请求接口
8. Web Browser组件的请求要想进入DinnerNow Web Service组件,后者必须提供一个提供程序接口用来响应。所以右键单击DinnerNow Web Service组件,选择添加->提供程序接口。
Figure 89 为DinnerNow WebService添加提供程序接口
9. 单击提供程序接口上的文本Interface2,将其修改为Customer Web Site。在属性选项卡中,将名称Port1修改为Customer Web Site
Figure 90 定义DinnerNow WebService提供程序接口的名称
10. 右键单击Web Browser组件的HTTP请求接口,选择添加->依赖。
Figure 91 添加依赖关系的右键菜单
11. 将依赖关系的另一头拖放到DinnerNow Web Service组件的Customer Web Site提供程序接口,并单击。
Figure 92 拖放依赖关系
Figure 93 建立依赖关系后的效果
12. 客户的订餐请求经过Customer Web Site接收后,进入DinnerNow Web Service执行,但是要想让内部的组件获得外部的请求,同样需要在内部组件上建立提供程序接口用来接收进入DinnerNow Web Service的请求。参考步骤10,为Customer Web Server组件添加一个名称为Sales的提供程序接口。
Figure 94 建立Sales接口
13. 在组件内部的各个部分之间,存在着消息或事件的传递,就是委托。所以,在消息内部的接口之间使用委托关系来表示消息的流向和事件的响应。参考步骤11,在Customer Web Site接口与Sales接口之间建立委托关系.
Figure 95 建立从Customer Web Site接口到Sales接口的委托关系
14. 进入Customer Web Server组件的订餐请求,经过处理之后,会执行两件事。一是向银行发送付款验证,二是将客户的菜单发送到厨房进行加工。由于银行属于DinnerNow Web Service组件的外部,且DinnerNow Web Service只需向银行发送付款验证请求即可。所以,参考步骤6、7,为Customer Web Server组件添加PaymentAuthorization请求接口
Figure 96 为Customer Web Server组件添加PaymentAuthorization请求接口
15. DinnerNow Web Service组件内部的部件要想将消息发送到组件外部的其他系统中,也需要一个向外的请求接口。所以参考步骤8、9,在DinnerNow Web Service组件左侧 边框上添加一个PaymentAuthorization请求接口,用来将Customer Web Server组件的PaymentAuthorization接口发送的消息传递到DinnerNow Web Service组件外部
Figure 97 为DinnerNow Web Service组件添加PaymentAuthorization请求接口
16. 参考步骤13,从Customer Web Server组件的PaymentAuthorization请求接口到DinnerNow Web Service组件的PaymentAuthorization请求接口建立委托关系。这样就完成了Customer Web Server向外部银行的消息传递。
Figure 98 从内部PaymentAuthorization接口到外部PaymentAuthorization接口建立委托关系
17. Customer Web Server组件的另一个功能是将客户的菜单送到厨房进行加工。所以,参考步骤14,为Customer Web Server组件建立另一个请求接口,名称为MealOrdering。
Figure 99 为Customer Web Server组件添加MealOrdering接口
18. 参考步骤12,为Kitchen Server组件添加一个提供程序接口,命名为MealOrdering。
Figure 100 为Kitchen Server组件添加MealOrdering接口
19. 由于Customer Web Server和Kitchen Server 两个组件同处在DinnerNow Web Service组件内部,所以 不需要消息的传递和事件机制,而应该建立直接的调用关系。右键单击Customer Web Server组件的MealOrdering请求接口,选择添加->部件引用。然后将鼠标拖放到Kitchen Server组件的MealOrdering提供程序接口上,建立 直接的程序集调用关系。
Figure 101 从 Customer Web Server组件的 请求接口 到 Kitchen Server组件的 MealOrdering提供程序接口建立部件程序集引用关系
20. Kitchen Server组件将接受来自厨房提交的菜品制作顺序,而Kitchen Server会按照制作顺序进行制作。真实的厨房应该属于DinnerNow Web Service组件外部的元素。所以,参考步骤8、9,在DinnerNow Web Service组件的右边界,添加一个提供程序接口,命名为Kitchen Web Site。再参照步骤18,在Kitchen Server组件上添加一个提供程序接口,命名为KitchenWorkQueue。并参考步骤13,从前者到后者建立委托关系。
Figure 102 建立Kitchen Web Site提供程序接口和KitchenWorkQueue提供程序接口,并建立二者之间的委托关系
21. 至此,我们完成了客户订餐到厨房加工几个环节的组件图,保存并关闭设计界面
Task 4 – 类图
软件设计建模中的UML类图描述了你的应用程序中使用的对象和消息结构。这些对象和消息,既包括系统内部的调用,又包含系统与用户的交互信息。它所描述的信息没有任何实现。它的类和关系可以使用多种方式实现,如数据库表、XML节点、或者软件对象组件。这个案例中,我们需要对用户需求建模中的概念类图进行一定的修改
1. 在解决方案浏览器中的ModelingProjectDinnerNow解决方案下,双击类图UMLClassDiagramDinnerNow.classdiagram,在设计界面中打开类图。
2. 由于菜单与菜单项之间是所有权的关系,而订单与订单项是整体与部分的关系,所以这里要修改Menu与MenuItem之间的关系为所有权关系。单击选中Menu类与MenuItem类之间的关系,并保持选中状态。打开属性选项卡,依次展开Navigation->First Role组。在First Role组中,找到Aggregation属性,并在下拉列表选项中将值Composite,修改为Shared,此时效果如下图所示,Menu与MenuItem类之间的关系变成了空心菱形的所有权关系
Figure 103 修改Menu类与MenuItem类之间的关系为所有权关系
3. 通常订单总是需要一个订单总价,所以我们为Order类添加一个保存总价的属性。单击Order类左上角的扩展箭头,展开Order类。
Figure 104 展开Order类
4. 右键单击Order类的Attributes组,在弹出的菜单中选择添加->属性
Figure 105 添加属性右键菜单
5. 此时,在Order类的属性组内出现一个可编辑的属性,文本为+Attribute1。保持可编缉状态,将文本+Attribute1修改为+TotalPrice。然后按下回车,确认修改。
Figure 106 修改TotalPrice属性名
6. 再次单击选中TotalPrice属性,在属性窗口中的常用属性组中找到类型属性。在下拉列表中输入Money。表示这个总价属性是货币类型。
Figure 107 修改TotalPrice属性的数据类型
7. 在Order类中,常用的对订单的操作,这里举两个例子。一个是添加订单项,一个是删除订单项。右键单击Order类的操作组,在右键菜单中选择添加->操作
Figure 108 为Order类添加方法菜单
8. 此时,在操作组内会出现一个可编辑的操作,文本为+ Operation1(),将其修改为+ AddItem()。按下回车,确认修改。
Figure 109 为Order类添加AddItem方法
9. Order类中的添加订单项方法,如果要执行,必须接受一个订单项,作为待插入的资源。单击AddItem操作,在属性选项卡中找到参数列表属性,单击属性值文本框中的省略号按钮,打开
Figure 110 打开参数列表属性的省略号按钮
Figure 111 操作参数集合编辑器
10. 如上图所示,点击左下角的添加按钮。在成员列表中选中自动添加的Parameter1参数,在右侧属性列表中,找到Name属性,将其修改为MenuItem,在Type属性的下拉列表中,选择ModelingProjectDinnerNow::MenuItem。单击确定完成参数的定义
Figure 112 为AddItem方法添加MenuItem参数
11. 参照步骤9、10,为Order类添加DeleteItem方法,并添加MenuItem参数。
Figure 113 添加DeleteItem方法
12. 通常餐厅除了支持网上下单外,更灵活的方式是电话订餐。此时生成的订单是电话订单。而电话订单中包含了普通订单的所有数据,但是却拥有一个特殊的属性,就是订单反馈的电话。在设计界面的右下角空白处,单击右键,选择添加->类
Figure 114 添加新类
13. 单击Class1类名部分,使其可编辑。将文本Class1修改为PhoneOrder。
Figure 115 修改PhoneOrder类名
14. 参照步骤4、5、6,为PhoneOrder类添加一个字符串类型属性:CallbackNumber
Figure 116 为PhoneOrder类添加CallbackNumber属性
15. 右键单击PhoneOrder类,在菜单中选择添加->继承。
Figure 117 添加继承菜单
16. 将鼠标移动到Order类上,直到出现连接标识。点击Order类,确认建立继承关系
Figure 118 建立PhoneOrder类到Order类的继承关系
Figure 119 建立PhoneOrder类到Order类的继承关系完成
17. 至此,更详细的类图的设计就完成了。保存并关闭当前设计界面
Exercise 3 代码浏览器
概述
当你需要修改现有软件系统时,Visual Studio旗舰版可以帮助你以可视化的方式理解组织结构、关系以及代码中的行为。在你修改代码之前,使用Visual Studio 旗舰版来浏览这些更改如何影响代码,从而帮助你评估风险和工作量。
Task 1 – 从现有代码生成图形化文档——查看Visual Studio解决方案中的源代码概要
1. 打开需要查看的Visual Studio 解决方案,这里我们使用PetShop.
2. 在Visual Studio 2010的顶部菜单中选择架构菜单。在架构菜单中选择生成依赖图形。接下来可选择以下选项之一执行
生成依赖图形 |
图形显示的内容 |
按照程序集引用 |
解决方案中的所有程序集间,以及内部程序集与外部依赖项之间的聚集依赖关系。 为了查看命名空间、类和内部方法,以图形化的方式展开引用。外部组件,只显示在项目中使用到的。 |
按照命名空间 |
解决方案中的所有命名空间之间,以及内部命名空间与外部依赖的命名空间之间的聚集依赖关系。 为了查看命名空间里的类和方法,以图形化的方式展开命名空间。外部命名空间,只显示在项目中使用到的。 |
按照类 |
解决方案中的所有类之间的聚集依赖关系。不会出现用到的外部类的信息。 |
Figure 120 生成依赖图形的菜单项
Figure 121 按程序集引用浏览的架构图
Figure 122 按命名空间浏览的架构图
Figure 123 按类结构浏览的架构图
Task 2 –从现有代码生成图形化文档——查看Visual Studio 解决方案中的源代码的特定依赖
利用架构资源管理可视化的查看你需要的代码和关系。
1. 打开需要查看的Visual Studio 解决方案,这里我们使用PetShop.
2. 如果架构浏览器没有打开,在架构菜单中,点击Windows->架构浏览器
Figure 124 从菜单打开架构浏览器
3. 在架构浏览器的第一列中的Visual Studio节点下选择如下两项:
l 类视图:用来查看代码的逻辑结构。以命名空间、类、方法等形式浏览。
Figure 125 类视图效果
l 解决方案视图:用来查看代码的物理结构。以项目、源文件等形式浏览。
Figure 126 解决方案视图效果
4. 选中类视图/解决方案视图,右侧会出现命名空间/项目列表。在列表选择你想查看的命名空间/项目。全选使用Ctrl+A。多选时,按住Ctrl。在第二列选择要查看的对象同时,第三列会弹出类/文件列表
5. 重复步骤4,选中你想要查看的对象。这里我们在命名空间/项目列表中选中:BLL。并使用Ctrl+A全选类型和成员列表中的所有项。
Figure 127 创建新的图形文档的按钮
6. 需要为你选中的对象建立新的关系图,请在架构浏览器的左上角标题栏下方,单击为你选择的节点创建一个新的图形文档按钮。此时Visual Studio 就会创建一个向导图形文档(.dgml),并打开它。
Figure 128 生成的向导图形文档
7. 到此,我们就成功将现有代码展示成了可视化文档。保存并关闭当前设计界面。