软工实践寒假作业(2/2)
| 这个作业属于哪个课程 | 2020春|S班 | 
|---|---|
| 这个作业要求在哪里 | 软工实践寒假作业(2/2) | 
| 这个作业的目标 | 学习使用GitHub、开发疫情统计程序 | 
| 作业正文 | 软工实践寒假作业(2/2) | 
| 其他参考文献 | 博客园、CSDN、简书、工程师的能力评估和发展 | 
GitHub仓库地址
《构建之法》及PSP表格
一个功能完备的程序不是一蹴而就的。我们可将一个大任务划分为可操作的小任务,同时最好按照任务难度或紧急程度指定各个任务的完成次序。因此,在动手开发之前,要先估计将在程序各模块开发所需耗费的时间,以及完成整个项目所需的时间,将这个[估计值]记录下来,写成PSP 的形式。
PSP的目的是记录工程师如何实现需求的效率,和我们使用项目管理工具(例如微软的Project Professional,或者禅道等)进行项目进度规划类似。
| PSP2.1 | Personal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟) | 
|---|---|---|---|
| Planning | 计划 | 60 | 45 | 
| Estimate | 估计这个任务需要多少时间 | 60 | 45 | 
| Development | 开发 | 600 | 900 | 
| Analysis | 需求分析 (包括学习新技术) | 120 | 180 | 
| Design Spec | 生成设计文档 | 30 | 40 | 
| Design Review | 设计复审 | 20 | 15 | 
| Coding Standard | 代码规范 (为目前的开发制定合适的规范) | 20 | 45 | 
| Design | 具体设计 | 30 | 60 | 
| Coding | 具体编码 | 300 | 420 | 
| Code Review | 代码复审 | 20 | 20 | 
| Test | 测试(自我测试,修改代码,提交修改) | 60 | 120 | 
| Reporting | 报告 | 100 | 120 | 
| Test Repor | 测试报告 | 30 | 25 | 
| Size Measurement | 计算工作量 | 10 | 20 | 
| Postmortem & Process Improvement Plan | 事后总结, 并提出过程改进计划 | 60 | 75 | 
| Total | 合计 | 760 | 1065 | 
解题思路
- 最近新型冠状病毒疫情严重,全国人民都感到担忧,迫切希望能够及时了解到病毒最新的情况,作为IT学子的我们需要帮忙开发一个疫情统计程序。于是我学习了助教提供的几个附录教程,了解并初步掌握了GitHub的使用。然后在百度上学习了命令行运行、main函数的参数等有关知识后,经过分析,我认为开发该程序主要由以下四个步骤组成
  
设计实现过程

代码说明
- 命令行代码
    public static void main(String[] args) {//命令行参数
        if (args.length < 1) {
            System.out.println("使用方式 java InfectStatistic list ");//使用方式
            return;
        }
        String action = args[0];
        if (!"list".equals(action)) {
            System.out.println("暂不支持其他操作");//报错
            return;
        }
        String inDir = "";
        String outDir = "";
        String date = "";
        List<String> types = new ArrayList<>();
        List<String> provinces = new ArrayList<>();
        int curType = 0;
        for (int i = 1; i < args.length; i++) {
            if (args[i].startsWith("-")) {
                curType = 0;
                if ("-log".equals(args[i])) {//设置读取路径
                    inDir = args[i + 1];
                    i++;
                } else if ("-out".equals(args[i])) {//设置输出路径
                    outDir = args[i + 1];
                    i++;
                } else if ("-date".equals(args[i])) {//设置截止时间
                    date = args[i + 1];
                    i++;
                } else if ("-type".equals(args[i])) {//设置病人类型
                    curType = 1;
                } else if ("-province".equals(args[i])) {//设置省份
                    curType = 2;
                }
            } else {
                if (curType == 1) {
                    types.add(args[i]);
                } else if (curType == 2) {
                    provinces.add(args[i]);
                }//添加要关注的命令行参数
            }
        }
        Lib lib = new Lib();
        lib.loadData(inDir, date);
        lib.Print(outDir, types, provinces);
    }  
- 读取截止日期前的文本
    public void loadData(String path, String endDate) {//读取截止日期前的文本
        File file = new File(path);
        File[] files = file.listFiles();
        SimpleDateFormat fmt = new SimpleDateFormat("yyyy-MM-dd");//日期格式
        Date eDate;
        try {
            eDate = fmt.parse(endDate);//解析截止日期
        } catch (ParseException e) {
            eDate = new Date();
        }
        if (files != null) {
            for (File f : files) {
                String filename = f.getName();
                if (f.isFile() && filename.endsWith(".txt")) {//索引
                    String shortName = filename.substring(filename.lastIndexOf(File.separator) + 1);
                    String dateStr = shortName.substring(0, shortName.indexOf("."));
                    try {
                        Date curDate = fmt.parse(dateStr);//解析当前日期
                        if (curDate.getTime() <= eDate.getTime()) {
                            loadFile(f);//当前日期小于截止日期则读取文本
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }
- 输出统计文本
    public void Print(String outFile, List<String> types, List<String> provinces) {//输出统计文本
        boolean showNational = false;
        if (types.size() == 0) {
            types.add("ip");
            types.add("sp");
            types.add("cure");
            types.add("dead");
        }//添加类型
        if (provinces.size() == 0) {
            showNational = true;
            provinces.addAll(provinceSet);
        } else {
            if (provinces.contains("全国")) {
                showNational = true;
                provinces.remove("全国");
            }//省份不包括全国
        }
        provinces.sort(Collator.getInstance(java.util.Locale.CHINA));
        try {
            File f = new File(outFile);
            PrintWriter pw = new PrintWriter(f);
            if (showNational) {
                StringBuilder n = new StringBuilder("全国");
                for (String t : types) {//选择显示类型
                    switch (t) {
                        case "ip":
                            n.append(" 感染患者").append(totalIp).append("人");
                            break;
                        case "sp":
                            n.append(" 疑似患者").append(totalSp).append("人");
                            break;
                        case "cure":
                            n.append(" 治愈").append(totalCure).append("人");
                            break;
                        case "dead":
                            n.append(" 死亡").append(totalDead).append("人");
                            break;
                    }
                }
                pw.println(n.toString());
            }
            for (String p : provinces) {//选择显示省份
                StringBuilder n = new StringBuilder(p);
                for (String t : types) {
                    switch (t) {
                        case "ip":
                            n.append(" 感染患者").append(statIp.getOrDefault(p, 0)).append("人");
                            break;
                        case "sp":
                            n.append(" 疑似患者").append(statSp.getOrDefault(p, 0)).append("人");
                            break;
                        case "cure":
                            n.append(" 治愈").append(statCure.getOrDefault(p, 0)).append("人");
                            break;
                        case "dead":
                            n.append(" 死亡").append(statDead.getOrDefault(p, 0)).append("人");
                            break;
                    }
                }
                pw.println(n.toString());
            }
            pw.println("//该文档并非真实数据,仅供测试使用");
            pw.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
- 疫情变化情况统计
    private void process(String str) {//疫情变化情况统计
        for (int i = 0; i < p.length; i++) {
            Matcher m = p[i].matcher(str);
            if (m.matches()) {
                String province = m.group(1);
                String province2 = "";
                int num = 0;
                if (i == 2 || i == 3) {
                    province2 = m.group(2);
                    num = Integer.valueOf(m.group(3));
                    operate(i, province, province2, num);
                } else {
                    num = Integer.valueOf(m.group(2));
                    operate(i, province, num);
                }
            }
        }
    }
    private void operate(int type, String province, int num) {//患者身体变化情况
        int ip, sp, cure, dead;
        provinceSet.add(province);
        if (type == 0) {//感染患者增加
            ip = statIp.getOrDefault(province, 0);
            statIp.put(province, ip + num);
            totalIp += num;
        } else if (type == 1) {//疑似患者增加
            sp = statSp.getOrDefault(province, 0);
            statSp.put(province, sp + num);
            totalSp += num;
        } else if (type == 4) {//感染患者死亡
            ip = statIp.getOrDefault(province, 0);
            statIp.put(province, ip - num);
            totalIp -= num;
            dead = statDead.getOrDefault(province, 0);
            statDead.put(province, dead + num);
            totalDead += num;
        } else if (type == 5) {//感染患者治愈
            ip = statIp.getOrDefault(province, 0);
            statIp.put(province, ip - num);
            totalIp -= num;
            cure = statCure.getOrDefault(province, 0);
            statCure.put(province, cure + num);
            totalCure += num;
        } else if (type == 6) {//疑似患者确诊
            ip = statIp.getOrDefault(province, 0);
            statIp.put(province, ip + num);
            totalIp += num;
            sp = statSp.getOrDefault(province, 0);
            statSp.put(province, sp - num);
            totalSp -= num;
        } else if (type == 7) {//疑似患者排除
            sp = statSp.getOrDefault(province, 0);
            statSp.put(province, sp - num);
            totalSp -= num;
        }
    }
    private void operate(int type, String outProvince, String inProvince, int num) {//患者流动情况
        int ip, sp;
        provinceSet.add(inProvince);
        provinceSet.add(outProvince);
        if (type == 2) {//感染患者
            ip = statIp.getOrDefault(outProvince, 0);
            statIp.put(outProvince, ip - num);
            ip = statIp.getOrDefault(inProvince, 0);
            statIp.put(inProvince, ip + num);
        } else if (type == 3) {//疑似患者
            sp = statSp.getOrDefault(outProvince, 0);
            statSp.put(outProvince, sp - num);
            sp = statSp.getOrDefault(inProvince, 0);
            statSp.put(inProvince, sp + num);
        }
    }
}
单元测试
- 
test1 
  
- 
test2 
  
- 
test3 
  
- 
test4 
  
- 
test5 
  
- 
test6 
  
- 
test7 
  
- 
test8 
  
- 
test9 
  
- 
test10 
  
代码规范链接
心路历程与收获
- 刚看到这次作业时,看到GitHub使用和命令行处理等一些之前没接触过的知识,我一头雾水,无从下手。在仔细阅读几遍作业要求和附录教程后,我才开始逐步按需求完成作业。在完成的过程中,我也遇到了一些问题,通过查询网络资料和教程,咨询同学和学长,我终于攻克了一个个难题,最终完成了作业。通过这次作业,我不仅收获了知识,还培养了自学能力,树立了自信心,这对于往后的学习和工作至关重要。
相关GitHub仓库
- 
Learn-Algorithms 
 该仓库是该用户学习算法过程的记录,包括了学习方法、基本数据结构和算法、算法设计思想、推荐阅读书籍、参考链接和学习网站等众多干货。
- 
JS-Sorting-Algorithm 
 一本关于排序算法的 GitBook 在线书籍《十大经典排序算法》,多语言实现。排序算法是《数据结构与算法》中最基本的算法之一,需要认真掌握。
- 
algo 
 数据结构和算法必知必会的50个代码实现,有13.7k的⭐Star,非常受欢迎。
- 
leetcode 
 leetcode 题典,包括了海量 leetcode 经典算法题目。
- 
Algorithms 
 全面的算法代码仓库,包含了各种算法的C++代码。
 
                
            
         
 
         浙公网安备 33010602011771号
浙公网安备 33010602011771号