博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
第三次作业结对编程
阅读量:7011 次
发布时间:2019-06-27

本文共 13590 字,大约阅读时间需要 45 分钟。

一、地址

  GitHub地址:

  本人学号:201731062329

  结对编程伙伴作业地址:

  作业地址:


 

二、结对过程

  我和我的搭档。选定了两方都有空的时间出来讨论,现制定了PSP表,然后根据各自水平,分配任务。各自的任务完成过后,先自审,再交由对方复审,然后汇总,封装成dll文件,进行单元测试和效能分析,并且改进代码,最后一起撰写博客。这是我们结对编程过程中的某一照片


 

三、PSP表格

PSP2.1

Personal Software Process Stages

预估耗时(分钟)

实际耗时(分钟)

Planning

计划

 880

 1395

· Estimate

· 估计这个任务需要多少时间

 880

 1395

Development

开发

 760

 1270

· Analysis

· 需求分析 (包括学习新技术)

 40

 50

· Design Spec

· 生成设计文档

 30

 35

· Design Review

· 设计复审 (和同事审核设计文档)

 50

 60

· Coding Standard

· 代码规范 (为目前的开发制定合适的规范)

 20

 15

· Design

· 具体设计

 30

 50

· Coding

· 具体编码

 400

 900

· Code Review

· 代码复审

 60

 40

· Test

· 测试(自我测试,修改代码,提交修改)

 100

 120

Reporting

报告

 120

 125

· Test Report

· 测试报告

 60

 60

· Size Measurement

· 计算工作量

 30

 40

· Postmortem & Process Improvement Plan

· 事后总结, 并提出过程改进计划

 30

 25

 

合计

 880

 1395


 

四、解题思路

  刚开始看到题目有点懵,感觉无从下手。于是就和自己结对编程的伙伴讨论了一下,确实是自己被题给“吓”到了,静下心来思考了一下,其实就是读写文件,将每一行读取的文件用字符串的Split()方法将其分割成字符串数组,对字符串数组中的每个元素进行讨论即可。例如统计字符总数,其实就是读取文件每一行数据,直接用str.Length,即可获取其一部分长度,无论是制表符还是空格,都能够准确得到其长度,唯一要注意的就是,回车符,这个也可以通过其文件的行数通过逻辑判断得出,最后汇总即可得到文件中字符的总数。详细的请看下面代码说明部分。在结对过程中找资料主要是上网查资料,以及通过自己以前的《面向对象程序设计》获取一些文件操作信息。


 

五、设计实现过程

  此次作业设计,由于编程经验不足,没有将功能设计规划的很好。对于此次作业,只有一个FileOperate类,在该类中将作业要求的几个点都封装在一个方法中,即一个方法对应一个功能。各个方法之间的关系除了判断一个字符串是否为一个单词的IsWords()方法会被其它方法调用,方法之间都是相互独立的。获取文件中字符总数的charNumber()方法、统计文件中单词总数的wordNumber()方法、得到文件行数的lineNumber()方法思路并不是很复杂,在此展示判断一字符串是否是一个单词的isWords(string word)方法、获取文件中的频率最高的n个词的wordTimes(int n)方法、获取文件中指定词组的wordGroup(int len)方法的流程图:

  由于双重循环在流程图中太复杂,能力有限将在后面代码说明处将对wordTimes(int n)方法、wordGroup(int len)方法进行详细的说明,实在抱歉。

  针对于单元设计,由于设计的方法都有返回值,所以在生成的单元测试环境中,都是创建一个FileOperate的对象,然后通过调用相应的方法,然后使用断言判断进行单元测试。


 

六、代码规范等

  结对讨论出的代码规范如下:

    1.命名规则:使用驼峰命名法。给类或函数或字段命名,使用具有相应中文意思的英文单词;

      2.分行:不把多条语句放在一行上,不把多个变量定义在一行上;

      3.断行与空白的{}行:”{“”}”单独在一行;

    4.注释:在类或方法的上面使用文档注释,在方法中使用普通注释;

  针对于FileOperate类中的charNumber()方法、lineNumber()方法、wordNumber()方法、isWords()方法、wordTimes()方法、wordGroup方法,搭档之间将本人负责后面四个部分,在我们完成相应的方法之后,自己先测试,通过以后,再相互审查,求同存异。在这其中发现了很多问题,令我印象深刻的一个就是,搭档提醒我,英语的语法特性,“,”、“.”、“!”前面如果有单词,这个字符串也应该算作一个单词,这个问题直到现在在脑海里还非常的清晰。


 

七、改进程序  

  刚开始的main函数比较臃肿,通过vs的性能分析工具发现,main函数消耗最大。通过观察发现,由于一些必要对命令行参数的操作,里面循环很多。在改进过程中时间大概花了10分钟,原来在刚开始的对"-o"、"-i"、"-help"命令的遍历时,如果找到了执行相应操作就可以终止了,但是实际上循环会有不必要的消耗,于是我就对循环添加了break关键字,以减少了不必要的消耗,使消耗略微的减少了。第二大消耗是我使用了linq语句用于字典排序,但这个,我并不是很熟悉其内部的消耗,所以就没有改进。

  消耗最多的函数

1 static void Main(String[] args)  2 {  3     //StreamWriter writeFile = new StreamWriter("out.txt", false);//false表示将文件覆盖,而不是追加  4     //FileOperate fileOperate = new FileOperate("input.txt", writeFile);  5     //初始化  6     string[] arg = new string[] { "-i", "input.txt","-o","out.txt","-n","3","-m","2" };//测试代码  7     StreamWriter writeFile = null;  8     FileOperate fileOperate = null;  9     //创建读文件对象 10     for (int i = 0; i < arg.Length; i++) 11     { 12         if(arg[i] == "-help" || arg[i] == "help")//可以直接使用help命令 13         { 14             Console.WriteLine("https://www.cnblogs.com/haveadate/ [version 3.0]"); 15             Console.WriteLine("(c) 2019 haveadate 保留所有权利。\n"); 16             Console.WriteLine("-i  参数设定读入的文件路径       (必要)     格式:-i [file]"); 17             Console.WriteLine("-o  参数设定生成文件的存储路径   (必要)     格式:-o [file]"); 18             Console.WriteLine("-m  参数设定统计的词组长度       (非必要)   格式:-m [number]"); 19             Console.WriteLine("-n  参数设定输出的单词数量       (非必要)   格式:-n [number]"); 20             Console.WriteLine("注: 参数顺序不对结果产生影响"); 21             return; 22         } 23         if(arg[i] == "-i") 24         { 25             fileOperate = new FileOperate(arg[i + 1]); 26             break;//减少不必要的运行 27         } 28     } 29     //创建写文件对象 30     for (int i = 0; i < arg.Length; i++) 31     { 32         if (arg[i] == "-o") 33         { 34             writeFile = new StreamWriter(arg[i + 1], false); 35             //三个必须输出 36             writeFile.WriteLine("characters: " + fileOperate.charNumber()); 37             writeFile.WriteLine("words: " + fileOperate.wordNumber()); 38             writeFile.WriteLine("lines: " + fileOperate.lineNumber()); 39             break; 40         } 41     } 42     //附加命令处理 43     for (int i = 0; i < arg.Length; i++) 44     { 45         if(arg[i].StartsWith("-"))//表明该项是输入参数 46         { 47             switch(arg[i]) 48             {                   49                 case "-m": 50                     int len = int.Parse(arg[i + 1]);//将字符串转换成数字                             51                     Dictionary
temp1 = fileOperate.wordGroup(len); 52 foreach (KeyValuePair
keyValuePairs in temp1)//Dictionary的foreach遍历对象自动转换成KeyValuePairs 53 { 54 writeFile.WriteLine(keyValuePairs.Key + ": " + keyValuePairs.Value); 55 writeFile.Flush();//将缓冲区的文件写到基础流 56 } 57 break; 58 case "-n": 59 int n = int.Parse(arg[i + 1]);//将字符串转换成数字 60 //Console.WriteLine(n); 61 Dictionary
temp2 = fileOperate.wordTimes(n); 62 foreach (KeyValuePair
keyValuePairs in temp2)//原理转换不是很清除,命名是推荐的 63 { 64 writeFile.WriteLine(keyValuePairs.Key + ": " + keyValuePairs.Value); 65 writeFile.Flush();//将缓冲区的文件写到基础流 66 } 67 break; 68 case "-help": 69 Console.WriteLine("https://www.cnblogs.com/haveadate/ [version 3.0]"); 70 Console.WriteLine("(c) 2019 haveadate 保留所有权利。\n"); 71 Console.WriteLine("-i 参数设定读入的文件路径 (必要) 格式:-i [file]"); 72 Console.WriteLine("-o 参数设定生成文件的存储路径 (必要) 格式:-o [file]"); 73 Console.WriteLine("-m 参数设定统计的词组长度 (非必要) 格式:-m [number]"); 74 Console.WriteLine("-n 参数设定输出的单词数量 (非必要) 格式:-n [number]"); 75 Console.WriteLine("注: 参数顺序不对结果产生影响"); 76 break; 77 case "-i": 78 case "-o": 79 break; 80 default: 81 Console.WriteLine("无效命令行参数,请重新输入!"); 82 Console.WriteLine("命令输入格式为:exeName.exe -[命令代号] [命令对应内容],命令可以无序使用" + 83 ",但必须有-i -o命令。\n想要了解更多,请在输入exeName.exe后输入-help命令"); 84 break; 85 } 86 } 87 } 88 89 //fileOperate.wordTimes(); 90 /* 91 fileOperate.charNumber(); 92 fileOperate.wordNumber(); 93 fileOperate.lineNumber(); 94 fileOperate.wordTimes(); 95 */ 96 fileOperate.closeFiles();//关闭文件流 97 writeFile.Close(); 98 Console.WriteLine("The result has been saved to the file, please check"); 99 Console.ReadKey();100 }
main

 

 

 

 


 

八、代码说明  

1 ///  2 /// 判断一个字符串是否是单词 3 ///  4 private bool isWords(string word) 5 { 6     char[] ch = word.ToCharArray();//将单词转换成字符数组 7     if(ch.Length < 4) 8     { 9         return false;10     }11     else12     {13         for(int i = 0; i < word.Length; i++)14         {15             if(i < 4)16             {17                 //如果前四个字符不为字母,就不是单词18                 if(!((ch[i] >= 'a' && ch[i] <= 'z') || (ch[i] >= 'A' && ch[i] <= 'Z')))19                 {20                     return false;21                 }22             }23             else24             {                        25                 //如果第五个字符开始出现非字母、数字,就不是单词26                 if(!((ch[i] >= 'a' && ch[i] <= 'z') || (ch[i] >= 'A' && ch[i] <= 'Z') || (ch[i] >= '0' && ch[i] <= '9')))27                 {28                     if(i == word.Length - 1)29                     {30                         if(ch[i] == ',' || ch[i] == '.' || ch[i]=='!')//若最后一个字符为","、"."、"!"前面也应该是单词31                         {32                             return true;33                         }34                     }35                     return false;36                 }37             }38         }39         return true;40     }41 }

 

  此方法请参照上面的流程图,不再赘述

1 ///  2 /// 统计每个单词出现的次数 3 ///  4 public Dictionary
wordTimes(int number) 5 { 6 reader.BaseStream.Seek(0, SeekOrigin.Begin);//将文件重新读取一遍 7 string temp;//临时的字符串变量 8 string[] tempArray;//临时的字符串数组,用于存储每一行的字符串数组 9 List
wordList = new List
();//存储单词的动态链表10 //将单词存储到List集合中11 while((temp=reader.ReadLine())!=null)12 {13 tempArray = temp.Split(' ');14 for(int i = 0; i < tempArray.Length; i++)15 {16 if(isWords(tempArray[i]))17 {18 if (tempArray[i].EndsWith(".") || tempArray[i].EndsWith(",") || tempArray[i].EndsWith("!"))//这里将英语标点符号的特性处理掉19 {20 char[] tempCharArray1 = tempArray[i].ToCharArray();21 tempArray[i] = new string(tempCharArray1, 0, tempCharArray1.Length - 1);//用字符数组的起始位置和长度创建字符串22 }23 wordList.Add(tempArray[i]);24 }25 }26 }27 int count;//临时变量count记录单词出现的次数28 Dictionary
wordsAndTimes = new Dictionary
();//用于存储单词以及他们的次数29 for(int i = 0; i < wordList.Count; i++)30 {31 count = 1;//单词本身就已经出现了一次32 temp = wordList[i];33 for(int j = i+1; j < wordList.Count; j++)34 {35 if(temp.ToLower().Equals(wordList[j].ToLower()))//不区分大小写的比较36 {37 count++;38 }39 }40 try41 {42 wordsAndTimes.Add(temp, count);//添加元素43 }44 catch//主要处理重复的情况45 {46 continue;47 }48 } 49 //使用linq语句排序,以前了解过,很管用,参考https://www.cnblogs.com/wt-vip/p/5997094.html50 var desSort = from tempElement in wordsAndTimes orderby tempElement.Value descending,tempElement.Key ascending select tempElement;51 /*52 foreach(KeyValuePair
keyValuePairs in desSort)//原理转换不是很清除,命名是推荐的53 {54 count++;55 writeFile.WriteLine(keyValuePairs.Key + ": " + keyValuePairs.Value);56 writeFile.Flush();//将缓冲区的文件写到基础流57 if (count == 10)58 {59 break;60 }61 }62 */63 Dictionary
keyValues = new Dictionary
();64 count = 0;65 foreach (KeyValuePair
keyValuePairs in desSort)//原理转换不是很清除,命名是推荐的66 {67 count++;68 keyValues.Add(keyValuePairs.Key, keyValuePairs.Value);69 if (count == number)70 {71 //Console.WriteLine("kkk");72 break; 73 }74 }75 return keyValues;76 }

  此方法首先通过循环读取输入文件中单词存储到List集合中,具体过程是没循环一次就读取文件中的一行数据,通过Split()方法将其分割成字符串数组,然后对字符串数组中的每个元素进行判断,若是单词就将其存储到List集合中。然后通过双重循环对List集合中的单词进行搜索,这个过程有点像交换法排序的方式,依次比较,在这个过程中用字典对单词及其出现的次数进行存储,,内层循环一次后就会得出某个单词的频率,用try语句尝试对单词进行存储,但可能单词已经存储了,所以catch直接进行下一次循环(后面的单词出现的次数没前面想通过单词的次数多,不够准确)。最后得到了每个单词及其出现的次数的集合,由作业要求,次数优先输出,其次考虑单词的字典顺序,上网查了一下,linq语句非常适合字典排序。最后就是返回指定长度的字典对象。这里,发现了一个小知识点,就是字典不能够直接用foreach语句输出,而是用对应的KeyValuePairs作为基本的对象。

1 ///  2 /// 词组统计:能统计文件夹中指定长度的词组的词频,约定,词组不能跨行 3 ///  4 ///  5 /// 
6 public Dictionary
wordGroup(int len)//代码复用比较多 7 { 8 reader.BaseStream.Seek(0, SeekOrigin.Begin);//将文件重新读取一遍 9 string temp;//临时的字符串变量10 string[] tempArray;//临时的字符串数组,用于存储每一行的字符串数组11 List
wordList = new List
();//存储单词的List集合12 while ((temp = reader.ReadLine())!=null)//读取文件13 {14 tempArray = temp.Split(' ');15 for(int i = 0; i < tempArray.Length + 1 - len; i++)//+1-len的原因是后面根本没有足够的词组成词组16 { 17 for (int j = 0; j < len; j++)//词组的判断18 {19 if((i+j)
wordsAndTimes = new Dictionary
();//用于存储单词以及他们的次数46 for (int i = 0; i < wordList.Count; i++)47 {48 count = 1;//单词本身就已经出现了一次49 temp = wordList[i];50 for (int j = i + 1; j < wordList.Count; j++)51 {52 if (temp.Equals(wordList[j]))//约定词组区分大小写53 {54 count++;55 }56 }57 try58 {59 wordsAndTimes.Add(temp, count);//添加元素60 }61 catch//主要处理重复的情况62 {63 continue;64 }65 }66 //使用linq语句排序,以前了解过,很管用,参考https://www.cnblogs.com/wt-vip/p/5997094.html67 var desSort = from tempElement in wordsAndTimes orderby tempElement.Value descending, tempElement.Key ascending select tempElement;68 Dictionary
keyValues = new Dictionary
();69 //count = 0;70 foreach (KeyValuePair
keyValuePairs in desSort)//原理转换不是很清除,命名是推荐的71 {72 //count++;73 keyValues.Add(keyValuePairs.Key, keyValuePairs.Value);74 /*75 if (count == number)76 {77 //Console.WriteLine("kkk");78 break;79 }80 */81 }82 return keyValues;83 }

  其实wordGroup()方法实际上只是在wordTimes()的基础上扩展了一下,很多地方都直接复用了wordTimes()的代码,在此之说明不同之处:应作业需求,词组的长度是可变的,即通过传入的参数确定词组的长度,同样的遍历每行元素,不过在遍历每个元素的同时,在下标不越界的条件下,通过循环将后面len - 1个元素也遍历一次,若发现后面元素中有非单词的字符串,则以这个元素开头得不到相应的词组,若都满足,那么就将其存入List的集合中,后面操作与wordTimes()方法大致一样。


 

九、单元测试

charNumber()方法的单元测试

 

   设计思路:由于每个方法都有返回值,故创建一个FileOperate对象,然后调用该方法,进行测试即可,其它单元测试见下

 

  

   

 

  


 

十、说明

  基本功能的实现:

  

 

  

  健壮性:

  

  基本实现了错误提示功能;

  新添功能: 仿照像cmd、matlab等等中的help命令:

  

 

  获得帮助路径不唯一:

  


 

十一、总结

  通过构建之法学习到的相关内容以及结对项目的实践经历,深刻认识到团队合作中方方面面的重要性,比如代码规范、团队交流、代码合并、单元测试等等都对项目至关重要,通过本次与搭档一起共同解决项目的过程中,学到了相互沟通、任务分配、规范管理等技巧,从这次两人结对编程映射出了将来参加工作的团队合作,总的来说收获蛮大的。此次解决项目,我认为是1 + 1 < 2,因为两人刚开始合作,需要时间去磨合,我相信在后面,做的越多,1 + 1 >> 2 ! 

 

转载于:https://www.cnblogs.com/haveadate/p/10652689.html

你可能感兴趣的文章
图说历届云栖大会精彩内容(长图鉴赏)
查看>>
切换到云思维模式 联想借力SAP实现全球采购转型
查看>>
欧盟批准释放700MHz频段 促进5G发展
查看>>
“打农药”都不省心:勒索病毒冒充王者荣耀外挂
查看>>
XCode 8.0 下 NSLog 打印不完全
查看>>
知乎的乌托邦之梦:“扭曲立场”能否让知识变现
查看>>
Telecity公司在英国数据中心UPS故障导致网络服务中断
查看>>
联想修复茄子快传(SHAREit)安全漏洞
查看>>
盘点:物联网产业的六大特征
查看>>
智慧城市研究述评
查看>>
思科和VMware的SDN解决方案竟可同时选择
查看>>
据实而用 浅析会议摄像机的选购
查看>>
美国会委员会建议禁止中国国企收购美国资产
查看>>
联想走出收购摩托罗拉阴影
查看>>
武汉使用电子标签技术监控餐厨垃圾
查看>>
漳州电信分公司10000号客服中心推出新媒体服务
查看>>
管中窥豹!从电子市场看安防行业的变与不变
查看>>
北京通州获批全国海绵城市建设试点
查看>>
思科预测未来五年全球IP流量CAGR为22%
查看>>
家庭光伏发电迟迟不见补贴 只好诉诸法庭
查看>>