第7章 从序列图到C++(www.cppentry.com)
在本章的一开始,我们会延续在前面章节里所提到的类图概念,说明序列图与类图之间的关联性;随后介绍序列图的主要用途、常用元素以及对应的C++(www.cppentry.com)代码。此外,在最后一小节中,我们还会介绍序列图的孪生兄弟—通信图。
7.1 序列图与类图的关联
类图未能提出操作的实现方法,这部分的细节设计,可通过序列图(sequence diagram)来呈现。虽然,我们可以从类图对应到C++(www.cppentry.com)程序中的类、属性、关系及操作的声明,但也仅止于此,对于操作的实现方法,还得搭配序列图才能获得。一般操作的实现方法,主要由下列四个部分组成。
1. 计算公式或算法—如果实现方法中,用到领域中独特的计算公式,或者是比较复杂特殊的算法时,实践中通常会使用简单的代码或伪码(pseudo code)再搭配说明文字来记录。因为过于细节的信息,并不适合采用图示来呈现,所以计算公式或算法无法记录在类图中,也不适合记录在序列图中。
2. 控制流程(control flow)—实现方法中经常有各式的控制流程,例如条件控制、循环控制。涉及到对象的流程控制,可以记录在序列图中;没有涉及到对象的部分,不会呈现在序列图中,因为过于繁琐。在图7-1的序列图中,使用了循环片段(loop fragment)来标记循环控制
内将调用哪几项操作。循环片段的图示采用带loop的大方框。
3. 调用操作—对象通常通过调用其他对象的操作来达成合作目的,形成了一群对象交互的情境,这是序列图表达的重点。所以在整张序列图中,横向的带箭头实线都代表一项调用,可能是调用对象自身的操作,如图7-1中的12号消息,但更多的情况是调用其他对象的公开操作。
4. 生灭对象—对象的产生与消灭也可以在序列图中表达,如图7-1中的1~4号消息前方标记了〈〈create〉〉,即特别指出调用建构式,不同于调用一般的操作。
除了表达实现方法之外,更重要的是序列图还能够表达执行期间的一群对象,为了合力完成某一个目的,调用操作的交互情况。所以,一个系统会有多张的序列图设计,每一张序列图仅描述系统某个目的或情境下的执行期间对象的交互情况。不同于类图,由于系统只有一个内部静态结构,所以逻辑上只有一张类图,实体上可能因为某个观点而将类图分成几张。
接着,通过下面这个案例来体验序列图7-1与类图7-2的绝妙搭配。这个案例的执行结果如图7-3所示,执行期间将输出如图7-4所示的一群对象,并且通过如序列图7-1的交互,最终计算出该账户的总资产。
 |
| 图7-1 序列图 |
程序清单7-1~7-9为C++(www.cppentry.com)的源代码,对应图7-1的序列图消息序号,如下所示。
1. main.cpp中行号13—Account myAccount;
2. main.cpp中行号14—myFund=new Fund(49.61);
3. main.cpp中行号15—myRegularBid=new RegularBid();
4. RegularBid.cpp中行号7、9和11—myItem=new BidItem(359.53);
5. main.cpp中行号16—myRegularBid->setFund(myFund);
6. main.cpp中行号17—myAccount.setRegularBid(myRegularBid);
7. main.cpp中行号19—myRegularBid->getUnit();
8. RegularBid.cpp中行号23、24—for控制流程及其中的itemObj[i]->getUnit();
9. main.cpp中行号20—myFund->getPrice();
10. main.cpp中行号22—myAccount.calcAsset();
11. Account.cpp中行号12到13—for控制流程及其中的regularBidObj[i]->calcAsset();
12. RegularBid.cpp中行号29—getUnit()
13. RegularBid.cpp中行号23到24—for控制流程及其中的itemObj[i]->getUnit();
14. RegularBid.cpp中行号29—fundObj[i]->getPrice();
 |
| 图7-2 类图 |
 |
| 图7-3 执行结果 |
 |
| 图7-4 对象图 |
程序清单7-1 Account.h
//// EX07_01
16. // Account.h
17. //
18. #pragma once
19. #include <cstdlib>
20. #include <vector>
21. #include "RegularBid.h"
22. using namespace std;
23. class Account
24. {
25. public:
26. void setRegularBid(RegularBid*);
27. int calcAsset();
28. private:
29. vector<RegularBid*> regularBidObj;
30. };
//// EX07_01
程序清单7-2 Account.cpp
//// EX07_01
16. // Account.cpp
17. //
18. #include "Account.h"
19. void Account::setRegularBid(RegularBid *theRBid)
20. {
21. regularBidObj.push_back(theRBid);
22. }
23. int Account::calcAsset()
24. {
25. int size,theAsset=0;
26. size=regularBidObj.size();
27. for(int i=0;i<size;i++)
28. theAsset=theAsset+regularBidObj[i]->calcAsset();
29. return theAsset;
30. }
//// EX07_01
程序清单7-3 Fund.h
//// EX07_01
13. // Fund.h
14. //
15. #pragma once
16.
17. class Fund
18. {
19. public:
20. Fund(float);
21. float getPrice();
22. private:
23. float price;
24. };
//// EX07_01
程序清单7-4 Fund.cpp
//// EX07_01
12. // Fund.cpp
13. //
14. #include "Fund.h"
15. Fund::Fund(float thePrice)
16. {
17. price=thePrice;
18. }
19. float Fund::getPrice()
20. {
21. return price;
22. }
//// EX07_01
程序清单7-5 RegularBid.h
//// EX07_01
18. // RegularBid.h
19. //
20. #pragma once
21. #include <cstdlib>
22. #include <vector>
23. #include "Fund.h"
24. #include "BidItem.h"
25. using namespace std;
26. class RegularBid
27. {
28. public:
29. RegularBid();
30. void setFund(Fund*);
31. int calcAsset();
32. float getUnit();
33. private:
34. Fund *fundObj;
35. vector<BidItem*> itemObj;
36. };
//// EX07_01
程序清单7-6 RegularBid.cpp
//// EX07_01
28. // RegularBid.cpp
29. //
30. #include "RegularBid.h"
31. RegularBid::RegularBid()
32. {
33. BidItem *myItem;
34. myItem=new BidItem(359.53);
35. itemObj.push_back(myItem);
36. myItem=new BidItem(892.85);
37. itemObj.push_back(myItem);
38. myItem=new BidItem(591.45);
39. itemObj.push_back(myItem);
40. }
41. void RegularBid::setFund(Fund *theFund)
42. {
43. fundObj=theFund;
44. }
45. float RegularBid::getUnit()
46. {
47. int size;
48. float theUnit=0;
49. size=itemObj.size();
50. for(int i=0;i<size;i++)
51. theUnit=theUnit+itemObj[i]->getUnit();
52. return theUnit;
53. }
54. int RegularBid::calcAsset()
55. {
56. return getUnit()*fundObj->getPrice();
57. }
//// EX07_01
程序清单7-7 BidItem.h
///// EX07_01
12. // BidItem.h
13. //
14. #pragma once
15. class BidItem
16. {
17. public:
18. BidItem(float);
19. float getUnit();
20. private:
21. float unit;
22. };
//// EX07_01
140 C++(www.cppentry.com)程序员UML实务手册
程序清单7-8 BidItem.cpp
//// EX07_01
12. // BidItem.cpp
13. //
14. #include "BidItem.h"
15. BidItem::BidItem(float theUnit)
16. {
17. unit=theUnit;
18. }
19. float BidItem::getUnit()
20. {
21. return unit;
22. }
//// EX07_01
程序清单7-9 main.cpp
//// EX07_01
42. // main.cpp
43. //
44. #include <cstdlib>
45. #include <iostream>
46. #include "RegularBid.h"
47. #include "Account.h"
48. #include "Fund.h"
49. using namespace std;
50. int main(int argc, char *argv[])
51. {
52. Fund *myFund;
53. RegularBid *myRegularBid;
54. Account myAccount;
55. myFund=new Fund(49.61);
56. myRegularBid=new RegularBid();
57. myRegularBid->setFund(myFund);
58. myAccount.setRegularBid(myRegularBid);
59. cout << "富邦长虹基金单位及净值: "
60. << "(" << myRegularBid->getUnit() << ")"
61. << "(" << myFund->getPrice() << ")" << endl;
62. cout << "总资产为: "
63. << myAccount.calcAsset() << endl << endl;
64. system("PAUSE");
65. return EXIT_SUCCESS;
66. }
//// EX07_01
总之,序列图与类图之间关系密切,主要有如下关联,我们会在接下来的小节中,针对此关联详细介绍。
1. 对象与类—序列图所列出的一群对象,皆根据类图中的类定义输出。
2. 链接与关系—序列图中的对象之间隐藏着链接(link),因为对象之间有链接,才能调用彼此的操作;而对象之间的链接,必须根据类之间的关、聚合、组合或依赖定义而产生。
3. 消息与操作—序列图中的对象能够调用自身的操作,或者调用其他对象的公开操作;这些操作皆须定义于类图的类里。