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

原文地址:https://www.cnblogs.com/zdc123/p/12330382.html