欢迎联系我QQ:932856012
放大
缩小

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

这个作业属于哪个课程 <2020春S班>
这个作业要求在哪里 <作业要求>
这个作业的目标 <编写疫情统计程序、学习GitHub使用、学习开发有关知识>
作业正文 https://www.cnblogs.com/xwh130/p/12331067.html
其他参考文献 菜鸟教程、CSDN

1.PSP表格

PSP2.1 Personal Software Process Stages 预估耗时(分钟) 实际耗时(分钟)
Planning 计划 40 45
Estimate 估计这个任务需要多少时间 40 45
Development 开发 600 570
Analysis 需求分析 (包括学习新技术) 30 25
Design Spec 生成设计文档 20 20
Design Review 设计复审 15 10
Coding Standard 代码规范 (为目前的开发制定合适的规范) 10 5
Design 具体设计 20 24
Coding 具体编码 400 376
Code Review 代码复审 60 70
Test 测试(自我测试,修改代码,提交修改) 45 40
Reporting 报告 95 100
Test Repor 测试报告 30 40
Size Measurement 计算工作量 30 30
Postmortem & Process Improvement Plan 事后总结, 并提出过程改进计划 35 30
合计 735 715

2.解题思路

 拿到题目刚开始有点不知所措(可能是理解能力的问题),后来和同学讨论了一下明白了具体要求,
 有了一个大致思路。在实践中慢慢摸索出来整个程序的编写。
 1.首先我选择的是Java语言,对于所要求的命令可以用args数组读取。
 2.对于各个省份的数据存储使用类Province,并使用数组将全国及各省按首字母排序。
 3.对数据处理并正确更新对应Province中的各个值(不能忘记初始化为0)。
 4.根据命令的要求将所需要数据写入对应的文件中。

思路

3.设计实现过程

模块图:

主要分为4个模块:
  1.文件读入:根据用户的命令读取相应的文件。
  2.Province类:定义Province类用来存储各个省的数据。
  3.数据处理:按要求处理各个类型数据,并保存给对应省。
  4.命令输出:按照用户输入的命令,将所需的数据输出到对应的文件。

模块

流程图:

1.首先需要正确的打开用户指定的文件。
2.定义Province类用来存储各个省的数据。
3.按行处理,并以空格提取行内容。
4.分5种情况,细分为8种情况,处理后应更新对象中的变量。
5.按照用户输入的命令,将所需的数据输出到对应的文件。

流程

4.代码说明

1.创建Province类,包含4个成员变量,以省份名构造。

public class Province{
		String name;        //省份名
		int infected = 0;   //确诊病例
		int mayInfect = 0;  //疑似病例
		int cure = 0;       //治愈出院
		int dead = 0;       //死亡病例
		public Province(String name){
			this.name=name;
		}
	}

2.按首字母顺序构造对象。

String[] pros = new String[]{"全国","安徽","北京","重庆","福建","甘肃","广东",
				"广西","贵州","海南","河北","河南","黑龙江","湖北","湖南","吉林","江苏",
				"江西","辽宁","内蒙古","宁夏","青海","山东","山西","陕西","上海","四川",
				"天津","西藏","新疆","云南","浙江"};
		Province[] provinces = new Province[32];
		for(int i=0;i<32;i++){
			provinces[i] = t.new Province(pros[i]);
			prs[i] = " ";
		}

3.处理list后的-date,-log,-out,-type,-province,如果没有指定相应的参数,会给予提示。

		if(cmd.equals("list")){
		for(int i=1;i<args.length;i++){
			if(args[i].equals("-date")){
				date=args[i+1];
			}
			else if(args[i].equals("-log")){
				local=args[i+1];
			}
			else if(args[i].equals("-out")){
				output=args[i+1];
			}
			else if(args[i].equals("-type")){
				for(int j=0;j<4;j++)
				if((j+i+1)<args.length) type[j] = args[i+j+1];       //记录type
				if(type[0].isEmpty()){
					System.out.println("请指定type!");
					System.exit(0);
				}                 
			}
			else if(args[i].equals("-province")){
				for(int j=0;j<args.length-i;j++)
				if((j+i+1)<args.length) prs[j] = args[i+j+1];       //记录省
				if(prs[0].isEmpty()){
					System.out.println("请指定省份!");
					System.exit(0);
				}
			}
	      }
		}
		else System.out.println("input right cmd.");

4.读取输入路径下的所有文件,如果date超过了最晚的日志,给出错误提示。
如果目录下并没有文件,也需要给出提示。

		String basePath=local;
		String[] List=new File(basePath).list();
		if (date.compareTo(List[List.length-1])>0) {    //判断日期是否合法
			System.err.println("日期超出范围");
			System.exit(0);
		}
		date = date+".log.txt";
		int res=List[List.length-1].compareTo(date);
		if(List[0].equals(null)) System.out.println("选定目录下无文件,请重新选择!");     //判断目录下是否有文件

5.当确定目录下有文件,如果刚好等于最晚一天,那么处理目录下所有文件。否则就从刚好等于date或者第一个小于的文件开始读取。
读取文件注意utf-8,避免乱码。按行读取,并将每行用split函数依据空格提取相关信息。
确定出省份名,以待后面对变量的更新。
之后的思路比较简单,就是对新增、流入、治愈、死亡、疑似排除、疑似确诊这6种情况的处理。

else{
		if(res==0) num = List.length;
		else {
			for(int i=List.length-1;i>0;i--){
				if(List[i].compareTo(date)<=0){
					num = i+1;
					i=0;
				}
			}
		}
		for(int j=0;j<num;j++){
		try {
			/*读取文件*/
			FileInputStream f = new FileInputStream(local+List[j]);
			InputStreamReader reader = new InputStreamReader(f, "UTF-8");
			BufferedReader bf = new BufferedReader(reader);

			String str = null,str0 = null;
			int a=0,b=0,sum=0;
			while ((str = bf.readLine())!= null){
				String[] line = str.split(" ");  ///以空格间隔提取内容
		    	for(int i=1;i<32;i++){
		    		if(pros[i].equals(line[0])) a = i;  //找到省份位置
		    		if(line[2].equals("流入")){
		    		if(pros[i].equals(line[3])) b = i;
		    		}
		    	}
		    	/*1、2新增感染或疑似*/
				if(line[1].equals("新增")){
			    	str0=line[3].substring(0,line[3].length()-1);
			    	sum = Integer.parseInt(str0);
					if(line[2].equals("感染患者")){
						provinces[a].infected += sum;
						provinces[0].infected += sum;
					}
					else if(line[2].equals("疑似患者")){
						provinces[a].mayInfect += sum;
						provinces[0].mayInfect += sum;
					}
				}
				/*3、4省流入省*/
				if(line[2].equals("流入")){
					str0=line[4].substring(0,line[4].length()-1);
			    	sum = Integer.parseInt(str0);
			 
					if(line[1].equals("感染患者")){
						provinces[a].infected -= sum;
						provinces[b].infected += sum;
					}
					else if(line[1].equals("疑似患者")) {
						provinces[a].mayInfect -= sum;
						provinces[b].mayInfect += sum;
					}
				}
				/*5、6治愈或死亡*/
				if(line[1].equals("死亡")||line[1].equals("治愈")){
					str0=line[2].substring(0,line[2].length()-1);
			    	sum = Integer.parseInt(str0);
			    	if(line[1].equals("死亡")){
			    		provinces[a].infected -= sum;
			    		provinces[a].dead += sum;
			    		provinces[0].infected -= sum;
			    		provinces[0].dead += sum;
			    	}
			    	else{
			    		provinces[a].infected -= sum;
			    		provinces[a].cure += sum;
			    		provinces[0].infected -= sum;
			    		provinces[0].cure += sum;
			    	}
				}
				/*7疑似确诊*/
				if(line[1].equals("疑似患者")){
					if(line[2].equals("确诊感染")){
						str0=line[3].substring(0,line[3].length()-1);
				    	sum = Integer.parseInt(str0);
						provinces[a].mayInfect -= sum;
						provinces[a].infected += sum;
						provinces[0].mayInfect -= sum;
						provinces[0].infected += sum;
					}
				}
				/*8疑似排除*/
				if(line[1].equals("排除")){
					str0=line[3].substring(0,line[3].length()-1);
			    	sum = Integer.parseInt(str0);
					if(line[2].equals("疑似患者")){
						provinces[a].mayInfect -= sum;
						provinces[0].mayInfect -= sum;
					}
				}
			}
			bf.close();
			f.close();
		} catch (IOException e) {
			// TODO 自动生成的 catch 块
			e.printStackTrace();
		}
	}

6.打开要写的文件,注意:需要判断指定路径的目录是否存在,不存在要创建,不然会报错。

		File f = new File(output);
		while(!f.getParentFile().exists()) {
            boolean mkdir = f.getParentFile().mkdirs();
            if (!mkdir) {
                throw new RuntimeException("创建目标文件所在目录失败!");
            }
       }
        FileOutputStream fop = new FileOutputStream(f);
        OutputStreamWriter writer = new OutputStreamWriter(fop, "UTF-8");

7.将-type指定的数据提取出来,放入print数组下。

for(int i=0;i<type.length;i++){
			
			for (int j = 0; j < 32; j++) {  
							if(type[i].equals("ip"))
							    print[j] += "\t感染患者"+provinces[j].infected+"人\t";
							if(type[i].equals("sp"))
							    print[j] += " 疑似患者"+provinces[j].mayInfect+"人\t";
							if(type[i].equals("cure"))
								print[j] += " 治愈"+provinces[j].cure+"人\t";
							if(type[i].equals("dead"))
								print[j] += " 死亡"+provinces[j].dead+"人\t";
				}  
			
		}

8.如果只含-type那么输出至文件。

如果-type、-province都有,输出指定省份至文件。
当然默认情况就是输出各项不全为0的省份数据至文件。

		/*-type*/
		if(prs[0].equals(" ")&&!type[0].equals(" "))
		for (int i = 0; i < 32; i++) { 
			
			  if(provinces[i].cure!=0||provinces[i].dead!=0
				||provinces[i].infected!=0||provinces[i].mayInfect!=0)
			  	writer.append(print[i]+"\n");
			}
		/*-province*/
		else if(type[0].equals(" ")&&!pros[0].equals(" ")){
			for(int i=0;i<32;i++){
				for(int j=0;j<prs.length;j++)
				if (prs[j].equals(provinces[i].name)) {
					writer.append(""+provinces[i].name+"\t感染患者"+provinces[i].infected+"人\t"
					+ "疑似患者"+provinces[i].mayInfect+"人\t治愈"+provinces[i].cure+"人\t死亡"+provinces[i].dead+"人\n");
				}
			}
		}
		else if(type[0].equals(" ")&&!pros[0].equals(" ")){
			for(int i=0;i<32;i++){
				for(int j=0;j<prs.length;j++)
				if (prs[j].equals(provinces[i].name)) {
					writer.append(""+provinces[i].name+"\t感染患者"+provinces[i].infected+"人\t"
					+ "疑似患者"+provinces[i].mayInfect+"人\t治愈"+provinces[i].cure+"人\t死亡"+provinces[i].dead+"人\n");
				}
			}
		}
		/*-type -province*/
		else if(!type[0].equals(" ")){
			for (int i = 0; i < 32; i++) {
				String[] s0 = print[i].split("\t"); 
				for(int j=0;j<prs.length;j++)
			  	if(prs[j].equals(s0[0])) writer.append(print[i]+"\n");
			}
		}
		/*默认情况*/
		else if(type[0].equals(" ")&&prs[0].equals(" "))
		for (int i = 0; i < 32; i++) {  
		   if(provinces[i].cure!=0||provinces[i].dead!=0
			||provinces[i].infected!=0||provinces[i].mayInfect!=0){
			   writer.append(""+provinces[i].name+"\t感染患者"+provinces[i].infected+"人\t"
			   		+ "疑似患者"+provinces[i].mayInfect+"人\t治愈"+provinces[i].cure+"人\t死亡"+provinces[i].dead+"人\n");
		   }		   
		}

5.单元测试和描述

1.首先对默认仅仅指定输入输出路径下的测试。
test1
2.再对增加-date 2020-02-12情况测试。
test2
3.测试-date、-type(单个参数)。
test3
4.测试-date、-type(多个参数)。
test4
5.测试-date、-province,在这里发现输出空,查找发现自己忘记写仅含-province,遂补充并测试。
test5
修改后的测试结果:
test6
6.测试-date、-type、-province
test7
7.测试日期超出范围,给出提示。
test8
错误提示:

test9

8.测试-province参数乱序时输出结果,按序排列。
test10
9.测试-date 2020-02-13
test11
10.测试-province输出信息为0的省份
test12

6.单元测试覆盖率优化和性能测试

覆盖率

初次进行测试,覆盖率只有60左右,查看代码发现是有些可以跳过的选择分支没有正确处理,导致每次执行都会过一遍那个部分的代码。
还有一些处理用户输入错误的语句,有必要存在,没有改动。

改进后:
cover

覆盖率达到77~93

cover1

cover2

cover3

性能测试

xn
xn2

7.git仓库及代码规范链接

8.心路历程和收获

  • 心路历程:第一次看到这个题目的时候有点不知所措,面对要解决的问题也没有头绪。当时想着先写写看吧,结果写了没多久,发现要求有些地方我理解出现了偏差,以至于前面写的内容都是无用功。之后想起来高中时候,老师说题目不会做的时候就要多读几遍,有时候就会有新的体会。后来我又把题目看了好几遍,对不清楚的地方询问了同学。
    思路有了,开始编程又遇到了一些困难,上网查资料学习,请教同学最终问题还是解决了。编程大体结束,在测试等环节也遇到了一些麻烦,比如:eclipse缺少那个覆盖率的插件、Jprofiler不会用等等。好在互联网就是解决问题的宝库,在自己的努力下还是解决了许多问题。
    总结下来就是:从不理解到了解,再到读懂,然后到实现经历了很多困难,好在都一一解决了。
* 收获:初次面对一些自己不懂的问题和要求时,不要急躁不要盲目动手开工以免造成时间上的浪费,稳住心态,多读几遍题,去领会题意。有时候也要虚心向同学请教,多多交流往往有不一样的收获。 再者就是在编写的过程中会遇到很多困难和bug,细心和耐心都是不可或缺的。测试阶段也是不容忽视的,因为一个好的成品是要能经得住各种情况的测试,所以不断测试不断改进是今后我应该学习的。这次 作业我收获良多,今后在学习道路上还要更进一步。

9.相关仓库

1.JavaGuide:https://github.com/Snailclimb/JavaGuide
简介:Java学习+面试指南,一份涵盖大部分Java程序员所需要掌握的核心知识。适合各个阶段的同学阅读学习。
2.Heart-First-JavaWeb:https://github.com/skyline75489/Heart-First-JavaWeb
简介:一个走心的 Java Web 入门开发教程,面向新手友好,容易上手,同时没有废话,有很多实用的例子适合入门者学习。
3.Java:https://github.com/chenhaoxiang/Java
简介:Java的学习之路,学习JavaEE以及框架时候的一些项目,结合博客和源码,让你受益匪浅,适合Java初学者和刚入门开始学框架者。
4.hibernate-orm:https://github.com/hibernate/hibernate-orm
简介:Hibernate的核心对象/关系映射功能,适合进一步学习Hibernate框架。
5.SpringAll:https://github.com/wuyouzhuguli/SpringAll
简介:循序渐进,学习Spring Boot、Spring Boot & Shiro、Spring Cloud、Spring Security & Spring Security OAuth2,博客Spring系列源码,帮助初学者学习Spring。

posted @ 2020-02-19 14:04  109肖玮昊  阅读(206)  评论(3编辑  收藏  举报