一个大气又可爱的标题

一、预估与实际

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

二、需求分析

我通过查询小学教学大纲的方式了解到,小学一年级加减法有如下的几个特点:

  • 加法有两种形式:

    (1)个位数 + 个位数
    (2)个位数 + 整十数

  • 减法也有两种形式:

    (1)整十数 - 个位数
    (2)个位数 - 个位数

  • 结果不能为负数

经过分析,我认为,这个程序应当:

  • 结果不能为负数,也不能大于100
  • 被减数必须大于减数
  • 形如 A + B,A和B都为个位,或其中之一为整十数
  • 形如 A - B ,A应该大于等于B

小学二年级乘除法有如下的几个特点:

  • 乘法只有表内乘法
  • 除法也是表内除法
  • 除和商都是个位数

经过分析,我认为,这个程序应当:

  • 除数不能为0
  • 被除数应该大于或等于除数
  • 积不能大于100
  • 除和商都是个位数

三、设计

1. 设计思路

说明你如何设计这个程序

比如:

  • 关键函数的流程图是怎样的?



  • 算法的关键的关键是什么?

    1. 需要对用户的“错误输入”进行提醒,并结束程序
    2. 需要根据不同的运算符号,制定不同的随机数生成规则

2. 实现方案

写出具体实现的步骤

比如:

  • 准备工作:先在Github上创建仓库,克隆到本地,在本地新建PSP1302文件夹
  • 技术关键点:
    • 思考应该采用哪种设计模式,这种模式是否便于后续的功能扩展和修改。
    • 代码的结构该怎么构建
    • 针对不同的运算符号,结合用户需求,制定不同的随机数生成规则
    • 正则表达式能更容易解决用户的错误输入

四、编码

请说明你如何按照设计思路进行编码,并记录你在开发中遇到的问题,与解决过程

1. 调试日志

记录编码调试的日志,请记录下开发过程中的 debug 历程

比如:

  1. 由于用户输入的参数是输入给主方法的args数组,则用户输入参数的个数不为2时,会抛异常。

    解决方法:在主方法的开头新增对“args.length"的判断,若args不为“1”或“2”则提示用户输入错误。

  2. 除法运算中,因生成的除数为0,会抛异常。

    解决方法:将代码“random.nextInt(10)”修改为“1+ random.nextInt(9)”,这样随机数生成的范围就从[0-9]变成了[1-9],就不会出现除数为0的情况

2. 关键代码

//RandomNumber是父类,调用工厂的静态方法,根据运算符号的不同,返回对应的子类对象
	RandomNumber ran = RandomNumberFactory.createRan(bean.getSymbol());
 	ran.createRandomAandB(bean);
public class RandomNumberFactory {
 	public static RandomNumber createRan(String symbol) {
 	//根据不同的运算符号,返回对应的“随机数生成”子类
 		RandomNumber ran = null;
 		switch (symbol) {
 		case "+":
 			ran = new RandomOfAdd();
 			break;
 		case "-":
 			ran = new RandomOfSubtract();
 			break;
 		case "*":
 			ran = new RandomOfMultiply();
 			break;
 		case "/":
 			ran = new RandomOfDiv();
 			break;
 		}
 		return ran;
 	}
 }

RandomNumber是父类,它有四个子类,分别是“加减乘除”的随机数生成类,有着各自的随机数生成规则。“RandomNumberFactory”是工厂类,该段代码运用了“简单工厂”的设计模式,工厂类可以根据运算符号的不同,实例化出合适的对象,通过多态,返回相对应的子类对象。

“简单工厂”的特点:专门定义一个类来负责创建其他类的实例,被创建的实例通常都具有共同的父类。

主要优点:将对象的创建过程进行了封装,用户不需要知道具体的创建过程,只需要调用工厂类获取对象即可。

3. 代码规范

请给出本次实验使用的代码规范:

  • 第一条:不使用“Magic Number”,都用有意义的英文名进行变量的命名
  • 第二条:不使用拼音进行命名
  • 第三条:采用驼峰式命名规则,类名以大写字母开头,变量名和方法名以小写字母开头
  • 第四条:代码中的命名均不能以下划线或美元符号开始,也不能一下划线或美元符号结束。
  • 第五条:左小括号和字符之间不出现空格;同样的,有小括号和字符之间也不出现空格。

并人工检查代码是否符合规范

五、测试

测试用例 预期结果 实际结果
dfsfh 1 输入有误,程序结束! 同预期结果
10 a 输入有误,程序结束! 同预期结果
-123 2 输入有误,程序结束! 同预期结果
001 2 输入有误,程序结束! 同预期结果
34567 输入有误,程序结束! 同预期结果
10 1 生成10道题的txt文本,并且是一年级的加减题 同预期结果
100 生成100道题的txt文本,并且是一年级的加减题 同预期结果
10 2 生成10道题的txt文本,并且是二年级的加减题 同预期结果

六、总结

请总结过程中的教训和经验,思考

  • 是否使用了“软件开发的基本策略:分而治之”,是否需要重构

    采用了分而治之的策略,基本做到了”一个类只实现一个功能“,将各个类的功能细分,这样对代码进行修改或者扩展时可能会相对容易些。

    对于重构了解的不多,但本程序的中类分的较细,避免了过大的类和过长的方法,代码的耦合性较低,并把大部分的成员变量都存储在Bean类中,并且都设为private,一定程度上提高了封装性。

  • “高质量的设计、规范的编码以及有效的测试是保证软件产品质量的三个重要方面”,你是否采用了相关的手段,是否需要重构

    • 采用了“简单工厂”,在于重构方面的理解还需要加强

    • 在测试方面,对于用户的错误输入,应该给更详细的提示,告诉用户到底哪输入错了

    • 在“高质量的设计”方面,测试了代码的运行时间,经测试,出一万道题(暂时撤销了题目数的限制)所花费的时间为2000ms,最后发现其实大部分时间都花在了字符串拼接上,因为我的代码中每生成一道题,就会执行一次

    • String s1 = s1 + “新增字符串”;
      

      由于String带有final的关键字,所以程序把大部分时间浪费在字符串的创建和销毁上。当我用StringBuffer代替String后,发现出一万道题代码的总时长从2000多毫秒降低到了40毫秒,如此恐怖的效率提升确实让我震惊。如此清晰地认识到StringBuffer和String在“拼接字符串”上效率的差别也许就是我这次编程的最大收获。