欢迎来到hy的博客

众里寻他千百度,蓦然回首,那人却在灯火阑珊处。
侧边栏

软件工程实践寒假作业(2/2)

软件工程实践寒假作业(2/2)

作业描述

这个作业属于哪个课程 2020春|W班
这个作业要求在哪里 寒假作业(2/2)作业要求
这个作业的目标 学习github的使用、设计完成疫情统计的程序
作业正文 软件工程实践寒假作业(2/2)
其他参考文献

1.Github仓库地址

项目使用java语言开发
本次项目的Github仓库地址:模拟疫情统计

初次使用github不是很熟悉,新建了一个自己的仓库用于程序的提交测试测试,fork作业的示例仓库后,不小心把example文件给覆盖了,后来重新设置了示例仓库为上流,尝试多次同步无果后,自建了一个example与源文件一模一样,不知道pull request的时候是不是会产生一些问题。

2.PSP表格

PSP2.1 Personal Software Process Stages 预估耗时(分钟) 实际耗时(分钟)
Planning 计划 30 60
  • Estimate|- 估计这个任务需要多少时间|30|60
    Development|开发|1210|1290
  • Analysis|- 需求分析 (包括学习新技术)|180|240
  • Design Spec|- 生成设计文档|30|10
  • Design Review|- 设计复审|10|40
  • Coding Standard|- 代码规范 (为目前的开发制定合适的规范)|60|80
  • Design|- 具体设计|240|150
  • Coding|- 具体编码|600|480
  • Code Review|- 代码复审|30|80
  • Test|- 测试(自我测试,修改代码,提交修改)|60|210
    Reporting|报告|100|155
    Test Report|- 测试报告|40|100
    Size Measurement|- 计算工作量|30|35
    Postmortem & Process Improvement Plan|- 事后总结, 并提出过程改进计划|30|20
    |合计||1340|1505

3.解题思路

1)命令行的处理

对于命令行的处理,一开始拿到题目的时候觉得比较简单,并没有细致的考虑一些错误的,奇怪但是正确的命令输入,导致了程序除了普通的命令可以处理以外,对于诸如:命令位置的变动,参数位置的变动,缺省命令,缺省参数并没有比较好的支持,后续在编程的实践中,对于这些不完善的,都做了一些改进,满足了程序设计要求。

2)日志文件的处理

福建 新增 感染患者 23人
福建 新增 疑似患者 2人
浙江 感染患者 流入 福建 12人
湖北 疑似患者 流入 福建 2人
安徽 死亡 2人
新疆 治愈 3人
福建 疑似患者 确诊感染 2人
新疆 排除 疑似患者 5人
// 该文档并非真实数据,仅供测试

对于此类文件编写符合输入格式的检测,满足要求则提取。(编码完成后突然发现用正则表达式匹配不是更加简单,后来我就悔不当初了|编程经验不足导致的拐弯陌路,后续会加强|)

3)输出文件

对于指定的命令行参数用于文件的输出,例如:

list -date 2020-01-22 -log D:/log/ -out D:/output.txt

该命令会读取指定目录下,指定日期之前的文件信息,并将结果输出的指定的目录下,我为了图个方便直接将系统默认输出位置重定向到了目标文件位置(以后还是少偷点懒)

全国 感染患者22人 疑似患者25人 治愈10人 死亡2人
福建 感染患者2人 疑似患者5人 治愈0人 死亡0人
浙江 感染患者3人 疑似患者5人 治愈2人 死亡1人
// 该文档并非真实数据,仅供测试使用

4.设计实现过程

本次项目主要实现函数有三个部分:
1.命令行解析函数

功能:用于分析命令行传递的参数,过滤错误信息,存储命令行的命令
image

2.读入日志文件

功能:用于分析目录下的日志文件信息,并将信息存储至程序中
image

3.输出结果文件

功能:指定目录下输出结果文件,满足命令行的格式要求
image

5.代码说明

针对上面提到的程序运行流程,给出下列代码:
InfectStatistic类内成员变量:

public static final int PROVINCE_CONSTANT = 31;
	private boolean[] valid;          // 默认false +1全国,判断每个省份是否输出
	private byte[][] c;               // 整体数据结构 +1全国,保存每个省份的信息
	private String c1;                //-log参数存储
	private String c2;                //-out参数存储
	private String c3;                //-date参数存储
	private String[] c4;              //辅助type类型存储
	private String[] c5;              //辅助province类型存储
	private int cindex_4;             //record type number
	private int cindex_5;             //record province number

使用枚举类型帮助方便的转换格式:

enum Province {
	全国, 安徽, 北京, 重庆, 福建, 甘肃, 广东, 广西, 贵州, 海南, 河北, 河南, 黑龙江, 湖北, 湖南, 吉林, 江苏, 江西, 辽宁,
	内蒙古, 宁夏, 青海, 山东, 山西, 陕西, 上海, 四川, 天津, 西藏, 新疆, 云南, 浙江;
}

简单的命令解析及合法性检验:

void analysisCommand(String[] args) {
		// TODO Auto-generated method stub
		int test = 0;
		for (int i = 1; i < args.length; i++) {
			if (isCommand(args[i])) {
				test = 0;
				if (isLog(args[i])) {
					test = 1;
				} else if (isOut(args[i])) {
					test = 2;
				} else if (isDate(args[i])) {
					test = 3;
				} else if (isType(args[i])) {
					test = 4;
				} else if (isProvince(args[i])) {
					test = 5;
				}
			} else {
				if (test == 1) {
					File file = new File(args[i]);
					if (!file.exists()) {
						System.out.println("-log文件名错误,'" + args[i] + "'文件不存在");
						System.exit(0);
					}
					if (!file.isDirectory()) {
						System.out
							.println("-log文件名错误,'" + args[i] + "'不是一个目录文件");
						System.exit(0);
					}
					c1 = args[i];
					c1 = c1.replace("\\", "/");// 路径符号修改
					// 路径末自动添加'/'
					if (!c1.substring(c1.length() - 1).equals("/")) {
						c1 = c1.concat("/");
					}
				} else if (test == 2) {
					File file = new File(args[i]);
					if (!file.exists()) {
						try {
							file.createNewFile();// 创建日志文件
						} catch (IOException e) {
							// TODO Auto-generated catch block
							System.out.println(
								"-out错误,'" + args[i] + "'不存在并且无法创建该文件");
							e.printStackTrace();
						}
					}
					c2 = args[i];
				} else if (test == 3) {
					c3 = args[i];
				} else if (test == 4) {
					if (args[i].equals("cure") || args[i].equals("dead")
						|| args[i].equals("ip") || args[i].equals("sp")) {
						c4[cindex_4++] = args[i];
					} else {
						System.out.println(
							"输入的-type类型错误,-type不具有'" + args[i] + "'类型");
						System.exit(0);
					}
				} else if (test == 5) {
					try {
						valid[Province.valueOf(args[i]).ordinal()] = true;
					} catch (IllegalArgumentException e) {
						System.out.println(
							"输入的-province类型错误,-province不具有'" + args[i] + "'类型");
						System.exit(0);
					}
					c5[cindex_5++] = args[i];
				}
			}
		}
		if(c1==null) {
			System.out.println("-log命令内容不为空");
			System.exit(0);
		}
		if(c2==null) {
			System.out.println("-log命令内容不为空");
			System.exit(0);
		}
	}

对于每个文件的简单读取方法(有些代码限于篇幅原因进行缩略,详情见仓库):
刚开始写这部分的时候大脑当机,什么都没想就写下去了,也是我悔不当初(正则表达式匹配不香吗?),结果无端地增加自己工作量。

void readFile(String filename) throws FileNotFoundException {
		File file = new File(filename);
		if (!file.exists()) {
			System.out.println("节点基本信息文件未找到");
			System.exit(0);
		}
		Scanner s = new Scanner(file);
		while (s.hasNext()) {
			String province = s.next();
			// int num=s.nextInt();
			// String de = s.next();
			Province pr = null;
			// 如果是注释则跳过
			if (province.equals("//")) {
				province = s.nextLine();
			} else {
				try {
					pr = Province.valueOf(province);
				} catch (Exception ex) {
					System.out.println("文件格式错误(省份读入异常)");
					System.exit(0);
				}
				/*
				 * c[pr.ordinal()][1]++; System.out.println(c[1][1]);
				 */
				String second = s.next();
				if (second.equals("新增")) {
					···
					}
				} else if (second.equals("感染患者")) {
					···
					}
				} else if (second.equals("疑似患者")) {
					···
					}
				} else if (second.equals("死亡")) {
					···
				} else if (second.equals("治愈")) {
					···
				} else if (second.equals("排除")) {
				    ···
					}
				} else {
					System.out.println("文件格式错误(省份后第一个参数错误)");
					System.exit(0);
				}
			}
		}
		s.close();
	}

文件的输出方式较为简单,上面的流程图已经写的比较详细,这里不再过多赘述(有些代码限于篇幅原因进行缩略,详情见仓库):

void writeDown(String[] args) {
    /*
     *这里写了一些其他的文件输出流,详情见仓库
     */
		try {
			PrintStream print = new PrintStream(c2);// 这里偷懒了,可以使用上面的输出流
			System.setOut(print);
		} catch (FileNotFoundException e1) {
			// TODO Auto-generated catch block
			e1.printStackTrace();
		} // 写好输出位置文件;
		for (Province e : Province.values()) {
			if (cindex_5 != 0) {
				// 给定province,输出合法省份
				if (valid[e.ordinal()]) {
					System.out.print(e);
					if (cindex_4 != 0) {
						// 给定type类型
						···//输出相应内容
						}
					} else {
						// 没有给定类型,默认输出方式
						System.out.print(" " + "感染患者" + c[e.ordinal()][0] + "人"
							+ " " + "疑似患者" + c[e.ordinal()][1] + "人" + " "
							+ "治愈" + c[e.ordinal()][2] + "人" + " " + "死亡"
							+ c[e.ordinal()][3] + "人");
					}
					System.out.print("\n");
				}
			} else {
				// 没有给定province,默认输出含有信息的省份
				if (c[e.ordinal()][0] != 0 || c[e.ordinal()][1] != 0
					|| c[e.ordinal()][2] != 0 || c[e.ordinal()][3] != 0) {
					System.out.print(e);
					if (cindex_4 != 0) {
						// 给定type类型
						···//输出相应内容
						}
					} else {
						// 没有给定类型,默认输出方式
						System.out.print(" " + "感染患者" + c[e.ordinal()][0] + "人"
							+ " " + "疑似患者" + c[e.ordinal()][1] + "人" + " "
							+ "治愈" + c[e.ordinal()][2] + "人" + " " + "死亡"
							+ c[e.ordinal()][3] + "人");
					}
					System.out.print("\n");
				}
			}
		}
		System.out.println("// 该文档并非真实数据,仅供测试使用");
		printParameter(); //输出命令行的参数
	}

6.单元测试截图和描述

单元测试的代码量较多(刚刚接触,不怎么熟练,太菜了,所以写了很多),
由于内容太多(看起来没有营养而且繁多),这里只列出部分的代码
命令行的测试:
image
读取文件测试:
image

7.单元测试覆盖率及性能测试

由于在程序的代码中很多行写了System.exit(0);//对于这种中断,类是e.printStackTrace();的语句,程序测试覆盖率统计不到这样的行,所以导致了一些方法的覆盖率并不是100%,对此我也很无奈。

  1. 下面是单元测试覆盖率:
    image
  2. 性能测试所用内存(暂无合适的优化方法):
    image

8.代码规范的链接

我的代码规范:mycodestyle.md

9.心路历程与收获

  1. 通过本次作业,了解与熟悉了git及github的简单使用方法,初步的认识了Java的单元测试与性能测试,这也是本次作业的最大收获。
  2. 对于一些作业中遇到的困难,能够不厌其烦地挖掘和探索如何解决问题的方法,培养了自己的耐心。
  3. 重温Java的基本语法以及一些类库的使用,对于Java的认识更加深刻。
  4. 好的程序员一定要制定好自己的编程规范,虽然本次作业的编程看起来并不优雅,但也初步的制定了一些自己的编程规范,并在以后的作业中能够严格执行。
  5. 书山有路勤为径,学海无涯苦作舟—我最大的心得体会

10.技术路线图相关的5个仓库

仓库名称 仓库简介 仓库地址
TensorFlow Models TensorFlow Models是一个开源存储库,可以找到许多与深度学习相关的库和模型。 TensorFlow Models
Keras Keras是一个高级神经网络API,用Python编写,能够在TensorFlow,CNTK或Theano之上运行。旨在完成深度学习的快速开发 Keras
Flask Flask 是一个微型的 Python 开发的 Web 框架,基于Werkzeug WSGI工具箱和Jinja2模板引擎,使用BSD授权。 Flask
scikit-learn scikit-learn是一个用于机器学习的Python模块,基于 NumPy、SciPy 和 matplotlib 构建。,并遵循 BSD 许可协议。 scikit-learn
Django Django 是 Python 编程语言驱动的一个开源模型-视图-控制器(MVC)风格的 Web 应用程序框架,旨在快速开发出清晰,实用的设计。 Django
posted @ 2020-02-17 15:01  黄毅122  阅读(296)  评论(2编辑  收藏  举报