欢迎来到李舸的博客

如果有天你忘了努力,那我就把科比的故事讲给你听。
扩大
缩小

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

代码规范链接

codestyle.md

心路历程与收获

  • 刚看到这次作业时,看到GitHub使用和命令行处理等一些之前没接触过的知识,我一头雾水,无从下手。在仔细阅读几遍作业要求和附录教程后,我才开始逐步按需求完成作业。在完成的过程中,我也遇到了一些问题,通过查询网络资料和教程,咨询同学和学长,我终于攻克了一个个难题,最终完成了作业。通过这次作业,我不仅收获了知识,还培养了自学能力,树立了自信心,这对于往后的学习和工作至关重要。

相关GitHub仓库

  • Learn-Algorithms
    该仓库是该用户学习算法过程的记录,包括了学习方法、基本数据结构和算法、算法设计思想、推荐阅读书籍、参考链接和学习网站等众多干货。

  • JS-Sorting-Algorithm
    一本关于排序算法的 GitBook 在线书籍《十大经典排序算法》,多语言实现。排序算法是《数据结构与算法》中最基本的算法之一,需要认真掌握。

  • algo
    数据结构和算法必知必会的50个代码实现,有13.7k的⭐Star,非常受欢迎。

  • leetcode
    leetcode 题典,包括了海量 leetcode 经典算法题目。

  • Algorithms
    全面的算法代码仓库,包含了各种算法的C++代码。

posted on 2020-02-18 20:52  李舸  阅读(115)  评论(0编辑  收藏  举报

导航