软工实践寒假作业(2/2)
软工实践寒假作业(2/2)
这个作业属于哪个课程 | 班级链接(福大2020春软工实践S班) |
---|---|
这个作业要求在哪里 | 寒假作业 (2/2) |
这个作业的目标 | 开发疫情统计程序,熟悉程序开发流程和github的使用,提高代码水平 |
作业正文 | 正文 |
其他参考文献 | 知乎,CSDN论坛 |
1.github仓库地址:https://github.com/zdc5511116/InfectStatistic-main
2.PSP表格
PSP2.1 | Personal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟) |
---|---|---|---|
Planning | 计划 | 30 | 30 |
Estimate | 估计这个任务需要多少时间 | 30 | 30 |
Development | 开发 | 350 | 465 |
Analysis | 需求分析 (包括学习新技术) | 20 | 25 |
Design Spec | 生成设计文档 | 20 | 30 |
Design Review | 设计复审 | 10 | 10 |
Coding Standard | 代码规范 (为目前的开发制定合适的规范) | 15 | 20 |
Design | 具体设计 | 20 | 25 |
Coding | 具体编码 | 250 | 300 |
Code Review | 代码复审 | 10 | 40 |
Test | 测试(自我测试,修改代码,提交修改) | 30 | 25 |
Reporting | 报告 | 140 | 170 |
Test Repor | 测试报告 | 20 | 20 |
Size Measurement | 计算工作量 | 30 | 30 |
Postmortem & Process Improvement Plan | 事后总结, 并提出过程改进计划 | 90 | 120 |
合计 | 530 | 670 |
3.设计思路
首先分离参数(比如用String的split方法),判断传入了什么参数,记录各个参数的参数值(数据可以用map的键值对保存)。
每种参数都需要有一个函数来实现相应的功能,根据记录的参数按特定的顺序一个个执行相应的方法。
在执行方法的过程发生未预期的错误直接结束进程并显示错误信息。
4.设计实现
1.日志中可能出现八种情况,根据不同情况划分不同的计算方法
新增 感染患者 :increaseInf()
新增 疑似患者 :increaseSus()
感染患者 流入 <省2> :infInflow()
疑似患者 流入 <省2> :susInflow()
死亡 :dead()
治愈 :cure()
疑似患者 确诊感染 :diagnose()
排除 疑似患者 :exclude()
2.根据参数的类型划分方法
-log参数:dolog()
-out参数:doOut()
-date参数:doDate()
-type参数:doType()
-province参数:doProvince()
3.数据结构
观察预期输出数据可知,使用某种数据结构即能保存省份名,又能保存省份数据便于简化编程,于是使用了java的Map接口。
因为输出数据需要按拼音数据排序,于是选择了LinkedHashMap实例。
LinkedHashMap<String,List> String为省份名,List为数据列表保存该省份四种数据,每个数据项用整型存储。
4.流程图
5.主要代码
1.读取日志信息,根据不同的参数选择不同的方法
private void doDate(String date) throws Lib.Exit { ListlogList = Lib.getLogFiles(logDirectory); DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd"); Date paramDate; BufferedReader reader = null; try { paramDate = dateFormat.parse(date); List nationalData = statistics.get("全国"); //全国数据 for (File log : logList) { Date logDate = dateFormat.parse(log.getName().substring(0, log.getName().indexOf('.'))); if(logDate.compareTo(paramDate) > 0) { //判断日志文件的日期是否小于等于给定日期 continue; } reader = new BufferedReader(new InputStreamReader(new FileInputStream(log), StandardCharsets.UTF_8)); String dataRow; while((dataRow = reader.readLine()) != null){ if(dataRow.startsWith("//")) { //忽略注释行 continue; } String[] data = dataRow.split(" "); //分割数据行 if(!outProvince.contains(data[0])){ outProvince.add(data[0]); } List provinceData = statistics.get(data[0]); //当前行的省份数据 List destProvince; //用于处理流入 switch (data[1]) { case INCREMENT: //处理新增 if (data[2].equals(INFECTION_PATIENT)) { //新增感染 increaseInf(nationalData, provinceData, Lib.parseData(data[3])); } else { //新增疑似 increaseSus(nationalData, provinceData, Lib.parseData(data[3])); } break; case EXCLUDE: //处理排除疑似 excludeSus(nationalData, provinceData, Lib.parseData(data[3])); break; case CURE: //处理治愈 cure(nationalData,provinceData,Lib.parseData(data[2])); break; case DEAD: //处理死亡 dead(nationalData,provinceData,Lib.parseData(data[2])); break; case INFECTION_PATIENT: //处理感染患者流入 destProvince = statistics.get(data[3]); infInflow(provinceData,destProvince,Lib.parseData(data[4])); break; case SUSPECTED_PATIENT: if(data[2].equals(INFLOW)){ //处理疑似患者流入 destProvince = statistics.get(data[3]); susInflow(provinceData,destProvince,Lib.parseData(data[4])); } else if(data[2].equals(DIAGNOSE)) { //处理确诊 diagnose(nationalData,provinceData,Lib.parseData(data[3])); } break; } } } }catch (Exception e){ throw new Lib.Exit(e.getMessage()); }finally { try{ if (reader != null) { reader.close(); } }catch (Exception e){ e.printStackTrace(); } } }
2.判断参数类型进而选用对应的方法
public void execute(String[] args) throws Lib.Exit { if(args.length == 1){ Lib.helpList(); //显示提示信息 throw new Lib.Exit("请按照提示输入命令"); } /*分离参数*/ int i = 1; while (i < args.length) { switch (args[i]) { case "-log": hasLog = true; if (++i >= args.length) { //如果-log后面没有给参数值 throw new Lib.Exit("-log参数缺少参数值"); } logParam = args[i++]; //-log后面跟着的参数为-log的参数值 break; case "-out": hasOut = true; if (++i >= args.length) { //如果-out后面没有给参数值 throw new Lib.Exit("-out参数缺少参数值"); } outParam = args[i++]; //-out后面跟着的参数为-out的参数值 break; case "-date": hasDate = true; if (++i >= args.length) { //如果-date后面没有给参数值 throw new Lib.Exit("-date参数缺少参数值"); } dateParam = args[i++]; //-date后面跟着的参数为-date的参数值 break; case "-type": hasType = true; while (++i < args.length && !args[i].equals("-log") && !args[i].equals("-out") && !args[i].equals("-date") && !args[i].equals("-province")) { //-type的参数值范围 typeParams.add(args[i]); } break; case "-province": hasProvince = true; while (++i < args.length && !args[i].equals("-log") && !args[i].equals("-out") && !args[i].equals("-date") && !args[i].equals("-type")) { //-province的参数值范围 provinceParams.add(args[i]); } break; default: throw new Lib.Exit("\"" + args[i] + "\"无法解析的参数"); } } /*执行相应的方法*/ if(!hasLog){ //log必须有 throw new Lib.Exit("缺少-log参数"); } if(!hasOut){ //out必须有 throw new Lib.Exit("缺少-out参数"); } if(!hasDate){ //如果没有data参数 dateParam=new SimpleDateFormat("yyyy-MM-dd").format(new Date()); //当前日期 } doLog(logParam); //读取日志路径 doDate(dateParam); //读取日志路径下相应日期的日志 if(hasType){ doType(typeParams); //需要输出的信息类型 } if(hasProvince){ doProvince(provinceParams); //需要输出的省份疫情信息 } doOut(outParam); //输出到指定的路径 }
2.读取日志信息,根据不同的参数选择不同的方法
private void doDate(String date) throws Lib.Exit { ListlogList = Lib.getLogFiles(logDirectory); DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd"); Date paramDate; BufferedReader reader = null; try { paramDate = dateFormat.parse(date); List nationalData = statistics.get("全国"); //全国数据 for (File log : logList) { Date logDate = dateFormat.parse(log.getName().substring(0, log.getName().indexOf('.'))); if(logDate.compareTo(paramDate) > 0) { //判断日志文件的日期是否小于等于给定日期 continue; } reader = new BufferedReader(new InputStreamReader(new FileInputStream(log), StandardCharsets.UTF_8)); String dataRow; while((dataRow = reader.readLine()) != null){ if(dataRow.startsWith("//")) { //忽略注释行 continue; } String[] data = dataRow.split(" "); //分割数据行 if(!outProvince.contains(data[0])){ outProvince.add(data[0]); } List provinceData = statistics.get(data[0]); //当前行的省份数据 List destProvince; //用于处理流入 switch (data[1]) { case INCREMENT: //处理新增 if (data[2].equals(INFECTION_PATIENT)) { //新增感染 increaseInf(nationalData, provinceData, Lib.parseData(data[3])); } else { //新增疑似 increaseSus(nationalData, provinceData, Lib.parseData(data[3])); } break; case EXCLUDE: //处理排除疑似 excludeSus(nationalData, provinceData, Lib.parseData(data[3])); break; case CURE: //处理治愈 cure(nationalData,provinceData,Lib.parseData(data[2])); break; case DEAD: //处理死亡 dead(nationalData,provinceData,Lib.parseData(data[2])); break; case INFECTION_PATIENT: //处理感染患者流入 destProvince = statistics.get(data[3]); infInflow(provinceData,destProvince,Lib.parseData(data[4])); break; case SUSPECTED_PATIENT: if(data[2].equals(INFLOW)){ //处理疑似患者流入 destProvince = statistics.get(data[3]); susInflow(provinceData,destProvince,Lib.parseData(data[4])); } else if(data[2].equals(DIAGNOSE)) { //处理确诊 diagnose(nationalData,provinceData,Lib.parseData(data[3])); } break; } } } }catch (Exception e){ throw new Lib.Exit(e.getMessage()); }finally { try{ if (reader != null) { reader.close(); } }catch (Exception e){ e.printStackTrace(); } } }
6.单元测试
1.单元测试部分展示与结果
基本参数的测试
@Test void testLogOut2() { String[] args = { "list" , "-out" , "D:/Java/InfectStatistic-main/test/result/listOut2.txt" , "-log" , "D:/Java/InfectStatistic-main/test/log" , }; InfectStatistic.main(args); }
全部参数的测试
void testAll() { String[] args = { "list" , "-log" , "D:/Java/InfectStatistic-main/test/log" , "-out" , "D:/Java/InfectStatistic-main/test/result/listOut10.txt" , "-date" , "2020-01-23" , "-type" , "ip" , "dead" ,"cure" , "-province" , "福建" , "浙江" , "河北" , "湖北" }; InfectStatistic.main(args); }
list命令的提示测试
void testListHelp() { String[] args = { "list" , }; InfectStatistic.main(args); }
测试单元覆盖率
7.性能测试分析
测试结果
由测试结果可以看出程序再doDate()这个方法耗时最久,由于时间问题就没再去优化了
8.代码规范
9.心路历程与收获
在之前的作业中,老师首先让我们通读了邹欣老师的《构建之法》这本书,让我对于一些相关的知识有了一定的了解,包括一些个人编程和团队合作的内容。但是同时也完成了对自己的一个分析,在第一篇博客当中写了自己的个人相关的内容,其中包括对未来的一些规划,这门课首先给我的印象就是很好玩,和其他课程不太一样,不是靠记忆,更多的是看个人的一些新颖的想法。
原本对这门课也想的是按照题目的要求完成任务就可以了,但是在第二篇博客内容开始的时候,自己慢慢地发现了自己还有很多不会的东西,我认为,做好一件事情不是看你能否把它完成,而是看你是否愿意去做,是否敢去做。在做的过程当中也有很多同学觉得任务太重,这个我确实不敢否认,在有限的时间内要完成一个简单项目的编码、重构、审核、合并、测试、效能分析、改进。每一项都很耗费时间,但是在这个过程当中我发现,难是难,但是都是干货!
10.技术之道
1.设计模式 Java版本
设计模式,很清楚
2.数据结构题目 c、c++版本
Data Structure And Algorithm(常用数据结构与算法C/C++实现)
3.数据结构教程
B站郝斌老师的详细讲解
4.技术路线特点
技术之路
5.java集合框架
深入理解Java集合框架