软工实践寒假作业(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 {
List logList = 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 {
List logList = 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集合框架

浙公网安备 33010602011771号