结对编程
一、博客开头
Github地址 | https://github.com/1517043456/WordCount.git |
结对伙伴博客 | https://www.cnblogs.com/xnch/ |
二、描述结对过程
三、PSP表格
Planning | 计划 | 20 | 30 |
.Estimate | .估计这个任务需要多少时间 | 400 | 600 |
Development | 开发 | 300 | 350 |
.Analysis | .需求分析(包括新技术学习) | 30 | 30 |
· Design Spec | · 生成设计文档 | 20 | 30 |
· Design Review | · 设计复审 (和同事审核设计文档) | 10 | 30 |
· Coding Standard | · 代码规范 (为目前的开发制定合适的规范) | 20 | 20 |
· Design | · 具体设计 | 30 | 30 |
· Coding | · 具体编码 | 300 | 500 |
· Code Review | · 代码复审 | 30 | 60 |
· Test | · 测试(自我测试,修改代码,提交修改) | 60 | 30 |
Reporting | · 报告 | 30 | 60 |
· Test Report | · 测试报告 | 60 | 30 |
· Size Measurement | · 计算工作量 | 30 | 30 |
·Postmortem & Process Improvement Plan | · 事后总结, 并提出过程改进计划 | 30 | 30 |
合计 | 1370 | 1640 |
四、解题思路描述
五、设计实现过程
1、需求分析
本次项目需要实现的主要功能:
- 命令行和指令的分解
- 文件的读取
- 字符统计
- 行数统计
- 单词数量统计、当个单词的统计
单词词频的统计和排序(输出频率最高的10个。频率相同的单词,优先输出字典序靠前的单词)
2、程序流程图
3、项目的类及其解决方案
4、类结构和单元测试的设计
5、代码规范和链接
本次代码的规范主要采用比较大众的一个规范,我们就在网上找了一份我们适合我们经常编写代码习惯且比较具体的代码规范。
代码规范链接
六、代码说明
- 1、指令解析
SplitKeys类
,用于将从控制台获取到的指令进行解析,并根据不同指令调用不同功能,相当于整个项目的调度中心。
(1)指令获得和调用
//混合指令的使用
for (; i < keys.Length; i++) {
if (keys[i].Equals("-i")&&keys[i+1]!=null)
{
fileUtil.Filepath = keys[i+1];
}
if (keys[i].Equals("-m"))
{
m = int.Parse(keys[i + 1]);
}
if (keys[i].Equals("-n"))
{
n = int.Parse(keys[i + 1]);
}
if (keys[i].Equals("-o"))
{
o = keys[i + 1];
}
}
当然这里也可以使用Directionary
来以键值对的形式进行存储,即Directionary<stirng,string>
中,存入<-i,input.txt>
指令,这样应该是十分标准的控制台指令存储形式,不过可能会加大代码的复杂性。
(2)、实例化两个类,以便于调用功能。
FileUtil fileUtil = new FileUtil();
Count count = new Count();
- 2、文件的读入和写出
文件的读入和写出由FileUtil类
进行,将txt文件读入,并在读入的过程中进行简单的字符数和行数的统计以及单词的分割,最终返回一个处理过后的单词链表,以及键最终结果进行写入txt文件。
(1)、文件的读入和字符数和行数的统计
try
{
StreamReader sr = new StreamReader(this.Filepath, Encoding.Default);
//用于存储读取后的单词
List<string> wordList = new List<string>();
//用于分割筛选出每行的字母数字
string argex1 = "\\s*[^0-9a-zA-Z]+";
//用于分割单词
string argex2 = "[a-zA-Z]{4,}[a-zA-Z0-9]*";
//读取一行
string readLine;
while ((readLine = sr.ReadLine()) != null) {
CountChar += readLine.Length;
CountLine++;
string[] wordArray = Regex.Split(readLine, argex1);
foreach (string word in wordArray) {
if(Regex.IsMatch(word,argex2))
wordList.Add(word);
}
}
sr.Close();
return wordList;
}
在读入的时候进行字符数的统计和行数的统计,提高了效率。
这里用到的两个正则表达式:
//用于分割筛选出每行的字母数字
string argex1 = "\\s*[^0-9a-zA-Z]+";
//用于分割单词
string argex2 = "[a-zA-Z]{4,}[a-zA-Z0-9]*";
(2)、将结果写入文件
try
{
string txtfile = output;
StreamWriter sw = new StreamWriter(txtfile);
sw.Write(result);
sw.Flush();
sw.Close();
Console.WriteLine(output+"文件写入完毕!");
}
catch (Exception e)
{
Console.WriteLine("文件写入失败!");
}
- 3、单词的相关统计和排序
(1)、单词和对应词频统计
public string CountWord(int n,FileUtil fileUtil) {
String resultWord = null;
//需要输出单词数
int instructionN = n;
//获取已经分割了的单词列表
List<string> wordList = fileUtil.getWordList();
//用于将单词进行排序和存储
Dictionary<string, int> keyValuePairs = new Dictionary<string, int>();
foreach (string word in wordList) {
if (keyValuePairs.ContainsKey(word))
{
keyValuePairs[word]++;
WordCount++;
}
else {
keyValuePairs[word] = 1;
WordCount++;
}
}
(2)、排序
var queryResults = from ni in result//字典序排序
orderby ni
select ni;
foreach (var item in queryResults)
{
resultWord += item.ToString()+"\n";
}
这里使用的是.NET3.0
提供的字典排序。
4、结果截图:
(1)、控制台结果截图:
(2)、output.txt文件输出截图。
七、单元测试结果
(1)初步测试
(2)、更据结果测试结果后更正后:
八、性能改进
本次性能分析,主要是从算法入手和设计入手。首先在初步完成项目后,我们就进行了一次项目性能分析,来查看哪里的优化效率和算法。
可见,当我们为了完成功能,将所有代码写到一起时,有的代码重复率十分高,消耗也大,耦合度也大。因此我们进行了相应的优化和改进。
当我们将代码进行整理后,代码的重复率下降,耦合性降低,同时也通过注入对象的方式减少了类实例化的开销。
八、总结
本次结对编程,和自己的老搭档兼室友许自欢一起进行的。整个过程还算和和谐。他经常给我指出问题,当遇到问题时总是及时的给出一个解决方案。两个人去完成一个项目,无论是前期查阅相关资料还是后期的编码,都更加的快速和有效。当出现问题时,两个人一起解决,不同的思考方式总是想到很多方法,很快的将问题解决掉。结对编程刚开始时,的确有点不适应,一个人在编程的时候另外一个人有点迷惑不知道干嘛,因为不太习惯对方的编程方式和写法,但是到了后面熟悉后速度和效率就提高了。