寒假作业(2/2)
寒假作业(2/2)
| 这个作业属于哪个课程 | [2020春福大软工实践W班] | 
|---|---|
| 这个作业要求在哪里 | [寒假作业(2/2)] | 
| 这个作业的目标 | 开发一个疫情统计程序 | 
| 作业正文 | [正文链接] | 
| 其他参考文献 | ... | 
1. Github仓库地址。
2.PSP表格
| PSP2.1 | Personal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟) | 
|---|---|---|---|
| Planning | 计划 | 30 | 35 | 
| Estimate | 估计这个任务需要多少时间 | 30 | 35 | 
| Development | 开发 | 1070 | 1135 | 
| Analysis | 需求分析 (包括学习新技术) | 60 | 80 | 
| Design Spec | 生成设计文档 | 30 | 25 | 
| Design Review | 设计复审 | 60 | 55 | 
| Coding Standard | 代码规范 (为目前的开发制定合适的规范) | 30 | 35 | 
| Design | 具体设计 | 300 | 350 | 
| Coding | 具体编码 | 500 | 510 | 
| Code Review | 代码复审 | 30 | 20 | 
| Test | 测试(自我测试,修改代码,提交修改) | 60 | 60 | 
| Reporting | 报告 | 100 | 120 | 
| Test Report | 测试报告 | 30 | 40 | 
| Size Measurement | 计算工作量 | 30 | 40 | 
| Postmortem & Process Improvement Plan | 事后总结, 并提出过程改进计划 | 40 | 40 | 
| 合计 | 1200 | 1290 | 
3.解题思路描述格
(1)思路
说实话,作业刚拿到手完全没有思路,最终按照 作业指引慢慢从易到难。
- 
前置要求
 - 
github初使用和代码规范制定
 - 
idea初始用
 - 
总结一句:其实就是各种软件的下载注册已经再次考验英语水平(学好英语真的很重要,电脑的内存也很重要。。。
 - 
分析需求
 - 
首先进行命令行的读取并解析
 - 
读入文件提取文件信息
 - 
用正则表达式的方式进行文本处理
 - 
最后将结果输出
 

(2)查找资料
- 根据作业及其附录中的各种资料初步理解git和github
 - 查找JProfiler的使用方法进行单元测试和性能分析
 - 查找java的基本知识和一些数据结构用法,例如ArrayList,HashMap
 
4.设计实现过程
1.类的设计
- InfectStatistic //总类
 - Province内部类 //存储省份信息
 - CmdArgs内部类 //解析命令行参数
 - InfectFileManager //文件处理包括读入和输出
 
2.全局变量
- 存储命令行参数和参数值
 - log_path;//日志路径
 - out_path;//输出路径
 - date;//日期
 - type_list;//要求的类型(ArrayList
)  - province_list;要求的省份(ArrayList
)  - province_str;//存储排序好的省份(String [])
 
3.关键函数的流程图


4.代码说明
Province类
static class Province{
        private String name;//省份名称
        private int ip;//感染
        private int sp;//疑似
        private int cure;//治愈
        private int dead;//死亡
        /**
         * 输出结果
         * @return String
         */
        public String printResult(){
            StringBuilder result = new StringBuilder(name);
            if(type_list != null && !type_list.isEmpty()) {//type有参数
                for (String s : type_list) {
                    if (s.equals("ip")) {
                        result.append(" 感染患者").append(ip).append("人");
                    }
                    if (s.equals("sp")) {
                        result.append(" 疑似患者").append(sp).append("人");
                    }
                    if (s.equals("cure")) {
                        result.append(" 治愈").append(cure).append("人");
                    }
                    if (s.equals("dead")) {
                        result.append(" 死亡").append(dead).append("人");
                    }
                }
            }
            else {//type没有参数
                result.append(" 感染患者").append(ip).append("人").append(" 疑似患者").
                        append(sp).append("人").append(" 治愈").append(cure).append("人").
                        append(" 死亡").append(dead).append("人");
            }
            return result.toString();
        }
        /**
         * 获得对应省份在数组province_str的对应位置
         * @return int
         */
        public int getPosition() {
            int position = 0;
            for(int i  = 0; i < province_str.length; i++) {
                if(province_str[i].equals(name)) {
                    position = i;
                    break;
                }
            }
            return position;
        }
    }
代码省略了get和set的部分,printResult()函数对传入的参数type进行处理,有啥加啥,这是我最直接的想法。getPosition()函数获得对应省份在数组province_str的对应位置,因为后面的HashMap<integer,Province>是对Integer进行排序,所以直接在Province类中获取对应索引。
class CmdArgs{
        String[] args;
        /**
         * 传入命令行参数数组构造
         * @param args 命令行参数数组
         */
        CmdArgs(String[] args) {
            this.args = args;
        }
        /**
         * 获得命令行参数值
         * @return boolean
         */
        public boolean checkCmd() {
            if(!args[0].equals("list")) {
                System.out.println("错误:命令不存在");
                return false;
            }
            if(!has()) {//判断命令是否有log和out参数
                System.out.println("错误:命令缺少必要的参数");
                return false;
            }
            for(int i = 1; i < args.length; i++) {
                switch (args[i]) {
                    case "-log":
                        i = getLogPath(i);
                        if (i == -1) {
                            System.out.println("错误:日志路径有误");
                            return false;
                        }
                        ...
                        break;
                    default:
                        System.out.println("错误:未知参数");
                        return false;
                }
            }
            return true;
        }
        /**
         * 判断该命令是否有对应的必要参数
         * @return boolean
         */
        boolean has() {
            return Arrays.asList(args).contains("-log") && Arrays.asList(args).contains("-out");
        }
       ...
    }
CmdArgs类获取命令中的参数和参数值并存储在全局变量。主要是根据索引值来获取对应的参数值,并不再细说。
/**
         * 类型判断
         * @param content 日志中的内容
         * @param province_list 要求输出的省份
         * @return ArrayList<province>
         */
        public ArrayList<Province> match(String content, ArrayList<String> province_list) {
            ArrayList<Province> result = new ArrayList<>();
            if(province_list != null && !province_list.isEmpty()) {
                for(String s : province_list) {
                    Province p =new Province(s, 0, 0, 0, 0);
                    result.add(p);
                }
            }
            String pattern1 = "(\\S+) 新增 感染患者 (\\d+)人";
            String pattern2 = "(\\S+) 新增 疑似患者 (\\d+)人";
            String pattern3 = "(\\S+) 感染患者 流入 (\\S+) (\\d+)人";
            String pattern4 = "(\\S+) 疑似患者 流入 (\\S+) (\\d+)人";
                    ...
                    while (matcher1.find()) {
                        addIp(result, matcher1);
                    }
                    while (matcher2.find()) {
                        addSp(result, matcher2);
                    }
                    while (matcher3.find()) {
                        moveIp(result, matcher3);
                    }
                    while (matcher4.find()) {
                        moveSp(result, matcher4);
                    }
                    ...
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
            return result;
        }
我将文件读取出的内容存取在string中,匹配时每读取一行匹配一行,并根据对应的方法新建对应的Province类并存入ArrayList
/**
         * 省份排序
         * @param result 省份集合
         * @return HashMap<Integer, province>
         */
        private HashMap<Integer, Province> sort(ArrayList<Province> result) {
            HashMap<Integer, Province> result_map = new HashMap<>();
            int country_ip, country_sp, country_cure, country_dead;
            country_ip = country_sp = country_cure = country_dead = 0;
            for (InfectStatistic.Province province : result) {
                country_ip += province.getIp();
                country_sp += province.getSp();
                country_cure += province.getCure();
                country_dead += province.getDead();
                result_map.put(province.getPosition(), province);
            }
            Province country = new Province("全国", country_ip, country_sp, country_cure, country_dead);
            result_map.put(0, country);
            return result_map;
        }
对省份排序,我用了HashMap<Integer, Province>,Integer是对应省份的索引,Province是对应省份的疫情情况信息,map会自动按照key排序。
6.单元测试截图和描述
7.单元测试覆盖率优化和性能测试
- 覆盖率
 - 性能测试
 
8.代码规范
9.心路历程与收获
- 刚上手的时候很绝望,所以的名词都很陌生,把作业看了一遍又一遍,最后还是根据作业的提示,从简到难,特别感谢助教的博客寒假第二次作业引导和分析,第一天真的觉得没有希望了,每天数着日子,最后还是一点一滴写出来了,感谢所有帮助我的小伙伴,也感谢自己没有放弃。噢利给!!!!
 - 收获:我能说我最大的收获是电脑内存炸了吗?不可以!!
我觉得这次作业要学习很多新的知识,git和github的使用之类的,还有idea这个可爱的IDE,单元测试中有很多需要改进的bug,真的不是代码打完了,就完了那回事了。还有最大的收获就是自己的意志力变强了,感谢自己么的放弃。 
                    
                
                
            
        
浙公网安备 33010602011771号