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