《构建之法》第四次作业——结对编程
博客开头
这个作业属于哪个课程 | https://edu.cnblogs.com/campus/xnsy/2019autumnsystemanalysisanddesign |
这个作业要求在哪里 | https://www.cnblogs.com/harry240/p/11524113.html |
github地址 | https://github.com/zjc-123/WordCount/tree/master/201731062321 |
结对同学博客地址 | https://www.cnblogs.com/9527abc/ |
结对同学学号 | 201731062321 |
结对过程
PSP表格
PSP2.1 |
Personal Software Process Stages |
预估耗时(分钟) |
实际耗时(分钟) |
Planning |
计划 |
30 |
40 |
· Estimate |
· 估计这个任务需要多少时间 |
45 |
50 |
Development |
开发 |
900 |
1080 |
· Analysis |
· 需求分析 (包括学习新技术) |
70 |
90 |
· Design Spec |
· 生成设计文档 |
20 |
20 |
· Design Review |
· 设计复审 (和同事审核设计文档) |
30 |
45 |
· Coding Standard |
· 代码规范 (为目前的开发制定合适的规范) |
40 |
30 |
· Design |
· 具体设计 |
60 |
70 |
· Coding |
· 具体编码 |
540 |
660 |
· Code Review |
· 代码复审 |
60 |
90 |
· Test |
· 测试(自我测试,修改代码,提交修改) |
120 |
180 |
Reporting |
报告 |
60 |
100 |
· Test Report |
· 测试报告 |
60 |
60 |
· Size Measurement |
· 计算工作量 |
20 |
20 |
· Postmortem & Process Improvement Plan |
· 事后总结, 并提出过程改进计划 |
25 |
20 |
|
合计 |
1125 |
1395 |
解题思路
1、基本功能
当阅读完项目需求说明后,我们的第一反应就是题目太长。经过讨论,我们觉得在此次的题目中有四个基本功能:一是统计整个文件的行数;二是统计文件的字符数(包括空格、换行符、标点);三是统计单词频率;四是输出单词长度有效词数。先是将题目要求的功能实现之后,再去考虑代码的规范优化。
1、ReadWord.cs类:用于统计单词出现频率和计算指定单词长度的单词数。
2、ReadChar.cs类:用于统计文件的行数和字符个数。
3、program.cs:获取命令进行相应操作。
4、通过switch(args[i])解析命令
2、程序大致流程图
部分实现代码
1、统计字符数和行数
- 正则表达式统计字符数和行数
string str = File.ReadAllText(path);
StreamWriter sw = File.AppendText(outpath);
int hz = Regex.Matches(str, @"[\u4E00-\u9FFF]").Count;//汉字
int en = str.Length;//字符
int num = Regex.Matches(str, @"\d").Count;//数字
int hang = Regex.Matches(str, @"\r").Count + 1;//行数
Console.WriteLine("汉字个数={0}\n字符个数(包括空格、标点、换行符)={1}\n数字个数={2}\n行数={3}", hz, en, num, hang);
2、统计单词频率和字典排序
- 利用正则表达式划分单词,用Dictionary的key和value记录单词和出现频率并进行排序
string paths = File.ReadAllText(path);
StreamWriter sw = File.AppendText(outpath);
Dictionary<string, int> frequencies = new Dictionary<string, int>();
frequencies = new Dictionary<string, int>();
string[] words = Regex.Split(paths, @"\W");
foreach (string word in words)
{
if (frequencies.ContainsKey(word))
{
frequencies[word]++;
}
else
{
frequencies[word] = 1;
}
if (word.Length < 4)
{
frequencies.Remove(word);
}
}
Dictionary<string, int> ff = frequencies.OrderByDescending(o ⇒ o.Value).ThenBy(p ⇒ p.Key).ToDictionary(p ⇒ p.Key, o ⇒ o.Value);//利用key和value排序
int count = 0;
Dictionary<string, int>.Enumerator hh = ff.GetEnumerator();
while (hh.MoveNext())
{
if (Len.Equals(hh.Current.Key.Length))
count = count + hh.Current.Value;
}
Console.WriteLine("文件中长度为" + Len + "的单词数:" + count + "个");
-利用dictionary中的key和value进行排序
Dictionary<string, int> ff = frequencies.OrderByDescending(o ⇒ o.Value).ThenBy(p ⇒ p.Key).ToDictionary(p ⇒ p.Key, o ⇒ o.Value);//利用key和value排序
代码互审
我们通过代码互审、代码互测揪出了一批bug,改正了很多错误的地方。有些是不影响代码的运行,但在输入一些字符后程序就退出或者出现异常了。特别严重的是文件位置字符串的输入,老是出现异常或者是null的问题,找不到路径的文件,后续的改进:我们增加了对输入的文件的路径字符串的限定和判断,这样就大大增加了程序的可靠性。又比如:在输出相应单词长度的字符的需求时,忘了限制字符串的长度,导致输出了一大串数据。
互审感悟:通过代码互审阶段,我们发现了很多自己没有发现的问题, 不同的人通过不同的方式、输入不同类型的数据进行测试,就会测出一些程序上的漏洞,大的漏洞甚至会影响程序的运行和输出错误的结果。这些都是自己一个人编程无法发现,也无法解决的问题。所以结对编程在小规模项目中应用的好处是显而易见的。
单元测试以及性能
对其中的三个方法进行测试
性能测试
可见wordCount.ReadWord.ReadW 占用百分比最大,优化主要以这个为主,对代码进行优化,减少代码间的重复调用,减少循环的调用,降低耦合等。
代码运行展示
1. 在控制台运行
2.在命令行操作
收获和感悟
在上本门课程之前,结对编程对我们来说是一个完全陌生的事务。在本次作业中尝试着使用结对编程这种模式来完成项目,渐渐发现了其在小规模项目和在我们学生学习中的好处。本次和队友结对的过程十分愉快,本来以为这种模式会浪费时间,但实际操作过程中发现这种模式却大大提高了效率。一开始读题目的时候感觉太长,我们将题目分解,画出流程图,分析解题思路,不到一个小时就大致确定了解题方法。如果两个人分开做,不使用结对编程,是完全不可能这么快完成的。真的是集思广益呀!再就是每个人都会有擅长的部分和不擅长的部分,在结对编程的过程中,我们互相学习,取长补短,使得自身编程能力也得到了很大的提升。最后就是不同的人对程序有不同的测试方法,会输入不同类型的测试数据进行测试,这样揪出了一批自己一个人很难甚至不可能发现的问题。总而言之,此次结对编程,我们合作得十分愉快,真正体验到了1+1>2!
参考资料
1.C#文本文件(.txt)读写
2.深入理解C# 第三章 用Dictionary来统计文本中的单词数
3.C#中Dictionary排序方式