目录
1.Github项目地址:
2.PSP表格及预估开发时间:
PSP2.1 | Personal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟) |
---|---|---|---|
Planning | 计划 | 30 | 20 |
· Estimate | · 估计这个任务需要多少时间 | 10 | 10 |
Development | 开发 | 1400 | 1700 |
· Analysis | · 需求分析 | 240 | 300 |
· Design Spec | · 生成设计文档 | 20 | 0 |
· Design Review | · 设计复审(和同事审核设计文档) | 30 | 0 |
· Coding Standard | · 代码规范(为目前的开发制定合适的规范) | 30 | 30 |
· Design | · 具体设计 | 120 | 180 |
· Coding | · 具体编码 | 600 | 720 |
· Code Review | · 代码复审 | 60 | 50 |
· Test | · 测试(自我测试,修改代码,提交修改) | 300 | 420 |
Reporting | 报告 | 120 | 180 |
· Test Report | · 测试报告 | 50 | 30 |
· Size Measurement | · 计算工作量 | 10 | 10 |
· Postmortem & Process Improvement Plan | · 事后总结,并提出过程改进计划 | 120 | 120 |
Total | 合计 | 1740 | 2070 |
3.教程与设计:
- Information Hiding,即信息隐藏,类似于大二面向对象编程中的代码封装。和授课老师常说的 “你要什么告诉我,我拿给你” ,区别于将口袋里的东西直接展示给使用者,封装后的代码隐藏实现需求的具体步骤,留下接口给使用者调用,或者类的方法的调用。在本次作业中,我们将计算部分的核心代码封装为一个Core类,并分离出来,为它配置了数个接口,让外界调用来获得期望的数据,但不对外暴露实现的具体方法,隐藏了代码的运行过程和信息。
- Interface Design,即接口设计,既是一种好的习惯也是一个非常重要的手段。通过将一个类集合成一个或几个特定的接口,使用户对于程序的使用通过接口来进行,符合面型对象的思想,同时也便于维护和扩展。本次作业里要求的两个接口nt gen_chain_word(char* words[], int len, char* result[], char head, char tail, bool enable_loop)和int gen_chain_char(char* words[], int len, char* result[], char head, char tail, bool enable_loop)就很直观的体现了单词链程序本身的特点,也便于测试。
- Loose Coupling,即松耦合,是指程序的不同功能之间耦合度较低,不互相依赖,任何一个功能的使用和修改对其他的功能影响不大。在本次作业中,要求将核心计算过程封装为Core单独分离出来,并产生dll文件,可以通过命令行来进行测试和调用。
4.计算模块接口的设计与实现过程:
- 深度优先算法(DFS)和拓扑排序、动态规划。将有长度的单词看做带权的有向边,通过将入度为零的节点(单词的首位字母)不断去掉,减少26*26的有向图中的点,得到一个拓扑序列,再按照得到的序列向最后一个(被指向最多的尾字母)延伸,记录途中的信息,就能得到“最长路径”(“-c”)。其他要求基本可以从该方法演变(“-w”可视为“-c”中边长度全为一,“-h”,“-t”即对最长路径的截取)而来。
5.UML:
6.计算模块接口部分的性能改进:
- 一开始独立设计时采用了DFS,用近乎暴力枚举的方式写了一个最长路径的算法,结果在跑测试数据时久久不能输出结果,思考后发现性能基本消耗在递归的过程中。于是采用了拓扑排序的方法,避免递归,并在尽量少的遍历次数下完成排序和路径的生成。再完成后面对一万左右的单词量就可以用几秒算出结果了。
7.Design by Contract:
- 契约式设计(编程)要求软件设计者为软件组件定义正式的,精确的并且可验证的接口,这样,为传统的抽象数据类型又增加了先验条件、后验条件和不变式。
- 契约式设计规定了一个程序模块确定的接口,让程序设计更精确,在多人共同开发时不会互相影响产生混乱。在结对编程中保证了设计接口时具备先验条件、后验条件和不变条件,能互相配合。
8.计算模块部分异常处理说明:
void judge() {
if (wflag == 1 && cflag != 1 && rflag != 1) {
wchain();
}
else if (wflag != 1 && cflag == 1 && rflag != 1) {
cchain();
}
else if (wflag == 1 && cflag == 1 && rflag != 1) {
cout << "ERROR, -w and -c can not be both requested!" << endl;
}
else if (rflag == 1) {
rchain();
}
}
- 不允许-w和-c两种方法同时使用。
if ((fopen_s(&fp, cpath, "r")) != 0) {
printf("file not exist\n");
}
- 对错误路径异常的输出。
9.界面模块与计算模块的对接:
for (int ar = 1; ar < argv; ar++) {
if (argc[ar][0] == '-') {
if (argc[ar][1] == 'w') {
wflag = 1;
if (argc[ar + 1][0] != '-') {
strcpy_s(cpath, argc[ar + 1]);
}
}
else if (argc[ar][1] == 'c') {
cflag = 1;
if (argc[ar + 1][0] != '-') {
strcpy_s(cpath, argc[ar + 1]);
}
}
else if (argc[ar][1] == 'r') {
rflag = 1;
}
else if (argc[ar][1] == 't') {
tflag = 1;
top = argc[ar + 1][0];
}
else if (argc[ar][1] == 'h') {
hflag = 1;
hop = argc[ar + 1][0];
}
}
}
在读入参数之后,进行命令行参数的处理,判断参数的正确性,并根据参数来分别调用Core模块中的接口进行计算。
10.结对过程:
11.结对编程及其优缺点:
结对编程:
- 优点:两人结对配合,能力有所互补,互相督促和帮助。
便于讨论问题,能在编程的同时交流想法,快速解决问题。 缺点:个人习惯不同,时间也难以统一,有时会带来一些麻烦。
个人优缺点:
- 优点:抗压能力较强,学习积极性较高,热心学习对方的长处。
缺点:个人能力薄弱。
结对同学优缺点:
- 优点:个人能力强,执行力强,项目进展推进快。
缺点:比较专心,交流较少。