GIT地址 | GITHUB克隆地址 |
---|---|
结对伙伴 | 余睿哲 |
伙伴学号 | 201831061417 |
伙伴博客地址 | 地址 |
一、PSP表格
二、接口的设计与实现过程
设计:
共五大类,其中计算方法类和命令行翻译类两个类需要设计对应的接口。
详细内容见下面思维导图(如果图片看不清可以适当放大网页观看)
各类之间的关系
CountMethodImpl类 为Main类提供各种算法
TranslateCommandImpl类 则翻译Main类传过去的命令行指令,并返回需要的参数
WriteFile类 主要用于文件读写
Test类 用于测试各种类中的方法能否正确实现
Main类 中执行主函数,集成所有功能。
关键函数及实现方法(见思维导图)
程序运行结果
注:有效行数与看到的行数不同的原因:文档窗口的大小不同,会导致显示的行数不同,如果文档窗口足够长,则该文章(测试文章)可显示为一行
用到的几种设计理念
Interface Design
Loose Coupling
设计了五大类,将各个部分分开,想要加减功能可以在对应的类中进行更新,对整体影响较小
Information Hiding
使用一些常量将ASCII码、条件语句以及循环的参数保存起来,即隐藏了数据也提高了代码的可读性。
三、代码复审
编码规范
参考《阿里巴巴JAVA开发手册》
开始阅读
还存在一定的问题是因为:
1、有一个类为最早写的测试类,里面有较多直接使用的数字(以后会多加注意)。
2、有变量定义为numberM和numberN,是符合小写驼峰命名法的,是插件扫描判断错误。
四、性能改进
性能改进
接口实现的函数中,大多数都需要用到循环,循环的时间复杂度不算多,但也不算少。所以在循环中减少不必要的循环,不如在需要跳出循环时跳出循环,减少循环次数等等,即可减少一定的时间消耗,从而提高性能。
性能工具:JProfiler(IDEA的性能测试插件)
性能分析图
主函数因为集成了所有工具类的方法,所以消耗最大
主函数代码如下
public static void main(String[] args) {
//输入命令行
Scanner scanner = new Scanner(System.in);
String cmd = scanner.nextLine();
//创建需要的对象
TranslateCommandImpl translate = new TranslateCommandImpl();
CountMethodImpl method = new CountMethodImpl();
WriteFile writeFile = new WriteFile();
//得到需要的参数
String inFile = translate.returnInFile(cmd);
String outFile = translate.returnOutFile(cmd);
int numberM = translate.returnNumberM(cmd);
int numberN = translate.returnNumberN(cmd);
//能否读到文件,不能则停止
try {
InputStream in = new FileInputStream(inFile);
}catch (IOException e) {
System.out.println("文件位置有误!");
return;
}
//用于保存各种数据
int characters, words, lines;
//词频Map中的长度
int length;
//判断有无-i, -o指令
String noFile = "null";
if(noFile.equals(inFile) || noFile.equals(outFile)) {
System.out.println("输入或者输出不能为空!");
return;
}
//用于保存单词集
List strings;
//定长单词集
List lengthWords;
characters = method.countCharacterNumber(inFile);
strings = method.countWordNumber(inFile);
words = strings.size();
lines = method.countLine(inFile);
lengthWords = method.statisticsWord(strings, numberM);
//得到词频的Map
List> frequency = method.countWordsFrequency(strings);
//保存定长词频
List> neededFrequency = new ArrayList<>();
//得到其长度,方便遍历
int maxLength = 10;
length = frequency.size();
//如果长度大于10,则把长度变成10
if(length > maxLength) {
length = 10;
}
//打印结果
System.out.println("字符总数是:"+characters);
System.out.println("有效单词数是:"+words);
System.out.println("有效行数是:"+lines);
System.out.println("单词的出现频率从高到低依次是:");
for(int i=0; i 0) {
System.out.println("定长为 "+numberM+" 的单词是:"+lengthWords);
}
//如果参数n大于Map中的大小,则打印有效个。
if(numberN > length) {
numberN = length;
}
if(numberN > 0) {
System.out.println("出现评率最高的前"+numberN+"个单词依次是:");
for(int i=0; i
五、单元测试及其覆盖率展示
测试有效行的计算
函数构造思路:得到数据后,打印文章行数
数据构造思路:文章中有空行,看程序能否正确判断
测试有效单词的读取
函数构造思路:得到数据后,统计有效单词数后打印
数据构造思路:文章中有部分非有效单词,看程序能否成功判断并存入单词集合中。
测试命令行参数的获取
函数构造思路:给定一条命令行指令,看能否正确地获得参数
数据构造思路:给定各种形式的命令行进行测试,看能否正确获得参数;以及命令行有问题时能否正确报错。
六、异常处理说明
注:异常处理都在主函数中直接进行测试
异常一:命令行没有 -i 或 -o指令
异常二:无法读取到文件
七、结对过程
描述:
这次很幸运能够找到也同样是写JAVA的同学余睿哲。分工明确,因为我在一开始就对这个程序的编写有比较明确的思路,所有完成了大部分代码的编写;相应的他完成了很多代码的审计工作。结对编程让我感到一个复杂程序的编写,因为两个人的合作与努力变得简单了。结对期间没有发生任何矛盾,每个人都把自己的做的那部分任务做到了最好。代码的编写期间也有过阻碍,通过两个人的共同思考解决了问题。让我真切的感受到1+1>2。