Github地址 | https://github.com/h1916955160/WordCount |
作业要求地址 | https://www.cnblogs.com/harry240/p/11524113.html |
结对伙伴博客地址 | https://www.cnblogs.com/749963470HSR/p/11670372.html |
结对伙伴学号 | 201731062420 |
(1). PSP表格
进行去零取整计算
PSP2.1 | Personal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟) |
Planning | 计划 | 30 | 50 |
· Estimate | · 估计这个任务需要多少时间 | 30 | 50 |
Development | 开发 | 1110 | 1390 |
· Analysis | · 需求分析 (包括学习新技术) | 60 | 50 |
· Design Spec | · 生成设计文档 | 60 | 40 |
· Design Review | · 设计复审 (和同事审核设计文档) | 60 | 50 |
· Coding Standard | · 代码规范 (为目前的开发制定合适的规范) | 30 | 20 |
· Design | · 具体设计 | 120 | 150 |
· Coding | · 具体编码 | 600 | 900 |
· Code Review | · 代码复审 | 60 | 60 |
· Test | · 测试(自我测试,修改代码,提交修改 | 120 | 120 |
Reporting | 报告 | 150 | 110 |
· Test Report | · 测试报告 | 60 | 30 |
· Size Measurement | · 计算工作量 | 30 | 50 |
· Postmortem & Process Improvement Plan | · 事后总结, 并提出过程改进计划 | 60 | 30 |
合计 | 1290 | 1550 |
(2). 计算模块接口的设计与实现过程
2.1 解题思路:
看到题目需求分析得大概得有七个功能,经思考设计了一个wordmodel类,把此六个功能模块化为六个函数加入其中,参数分析函数在program类中(具体内容下面解析)
1、字符计数功能函数
通过网上信息资料查询,发现用正则来计算是最简单的,正则表达式来匹配计算文本的字符数,包含一些特殊字符都计算了的,但是也要注意正则的运用。
2、行数计数功能函数
同样采用正则匹配计算行数,值得注意的是记得计算结果记得加一,因为最后一行是没有换行符的。
3、单词计数功能函数
单词计数功能是结对队友写的,他没有采用正则匹配的方法,而是采用字符串转字符数组方法硬匹配,虽然算法不是比较优良,但是简单易懂。
4、词组拼接以及计数功能函数(此处有传参数,参数是-m后跟的参数,参数解析函数会在后面)代码太多就不放完了。
值得注意的是,最开始文本内容分隔单词后存进的string数组并不是只有分隔的单词数那么多个(采用的是字符串的split函数多个分隔符分割),在每个单词中间还存在有一个为空(不是空格)的字符串占位(调试发现),所以需要注意图中要跳着走,而不是挨个遍历。
5、排序函数
采用的是选择排序,单词集合list排序优先级是词频,在词频相同的情况下再实行字典序排序。代码过多就不放代码展示了。
6、文件输出功能函数(参数分析后有传入输出目的文件名)
把所有需要输出到文件的内容写成一个list集合,然后调用最后一句代码直接写入文件。
7、参数分析函数
对参数args字符串数组的参数进行解析,如果-m或者-n参数没有传参,则对他们进行初始化,然后传入各个函数中。
8、最后再main函数中对Countmodel对象实例化,并调用相关函数,实现单词统计
9、wordmodel类的属性展示
实现效果图:
2.2 程序流程图:
2.3 “Design by Contract”、“Information Hiding”、 “Interface Design”、 “Loose Coupling”等原则的体现
- Design by Contract:契约式设计就是按照某种规定对一些数据等做出约定,如果超出约定,程序将不再运行,例如要求输入的参数必须满足某种条件
对输入的参数解析判断,是否输入满足条件,正确了才能继续执行程序,否则将会停止程序。
- Information Hiding:信息隐藏指在设计和确定模块时,使得一个模块内包含的特定信息(过程或数据),对于不需要这些信息的其他模块来说,是不可访问的。
避免循环依赖,各自类没有调用其他类的子程序。而且类的(大部分,少部分没有)数据成员都是private,所有访问都是通过访问函数实现的;
- Interface Design:接口设计,对接口的继承,依赖关系,以及命名等相关方面的规范
- Loose Coupling:松耦合,也称低耦合,指程序模块间的依赖性程度,其耦合程度取决于程序模块的间的复杂关系,
一般通过增加抽象类或者接口实现模块的低耦合。
(3). 代码复审过程
代码规范:https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/inside-a-program/coding-conventions
在结对编程的过程中,我们俩进行了分工,各自做了一部分,然后审查对方的代码,也发现了许多问题。
- 命名问题突出,函数名首字母没有大写,变量名混乱不易理解
- 代码偶尔没有缩进
- 注释有的在程序语句后面,没有另起一行。
- 以及一些算法程序的逻辑错误
代码规范让我在复查中找到了许多不足的地方,同时也加深了自己对规范的态度,没有满足规范的代码就像一团打结的毛线,让人无从下手。有一个良好的代码规范,看着程序让人是真的赏心悦目,甚至能像一个艺术品一样带给我们“美”的感受。
(4). 计算模块部分单元测试展示
设计测试代码,运行查看,全部运行成功
单词计数函数模块:判断返回值是否和期望值相同,同理,字符统计和行数统计的模块测试原理一样就不都放出来了
词组拼接统计模块:模块运行后,通过判断集合列表是否为空,为空说明没有成功
输出文件模块:通过对输出文件的内容读入判断是否为空来判断是否写入成功,内容在其他其他测试模块测试了
排序函数:通过对排序后的集合列表查看是否为期待值,相同则正确,不同则报出异常
(5). 性能分析及改进
性能分析器勘察程序性能:
进入详细查看性能分析:
性能改进:
改进前:Countword函数调用正则匹配计算
代码情况:正则匹配计算
改进后:采用直接循环遍历单词,转化为字符数组匹配计算,改进后函数时间降低
改进代码:
通过比较发现,在main函数中,CountWord函数的花费时间变化,第一个是采用的正则匹配,第二个是字符数组匹配计算,正则的代码量少,比较精炼,但花费时间较多,而第二种字符数组匹配,虽然代码量较多。但是其花费时间反而更少了。
(6). 异常处理说明
在参数分析函数里,对传进来的参数进行异常分析:当用户输入命令时输错时产生异常信息
运行查看结果
换其他不正确的命令观察结果得:
(7). 结对的过程
与队友一起找了个安静的地方,有空就在一起结对编程,我们俩一起进行需求分析,代码设计,代码实现等过程,当一人有错的时候,另一人能及时给提出问题,或者提出好的想法。结对编程真是非常的方便,其中也有许多的乐趣。
(8). 代码提交
代码提交过程:
1. 先用git status命令查看是否都commit了
2. 执行 git add . 和 git commit -m "message" 命令
3. 执行git push命令上传
4. 向源仓库发起pull Request(发起请求给仓库贡献代码)
(9)总结
在结对编程开始前,觉得虽然是两个人一起编程,但是两个人 风格和能力都是不同的,担心会导致效率降低。开始编程时,两个人之间还不太熟悉,所以进展不算快,慢慢的熟悉之后,两人的效率大幅度提高,需求分析时,一同分析,简直事半功倍,而且想的也很全面,代码设计时,一人主导,另一人就负责提出问题,提出方案,然后两人谈论最终解决方案,分工合作,效率极高,而且也少了很多错误,一加一还真不一定等于二,另外就是编代码的时候了,各自负责各自的模块,而且由于代码设计好,工作量更是减少很多。让我做有收获的时最后的代码审查,代码复审,让我在找他人错误的同时,也反省自己并加深印象,而对方的评审找出自己平时的各种坏习惯,这些都是需要注意的地方,以后少走弯路。
--