个人作业1
——四则运算题目生成程序(基于控制台)
源代码地址:https://git.coding.net/pyj76566/Homework.git
a.需求分析:
自动生成小学四则运算题目的命令行 “软件”,满足以下需求:
- 除了整数以外,还要支持真分数的四则运算,真分数的运算,例如:1/6 + 1/8 = 7/24
- 运算符为 +, −, ×, ÷
- 并且要求能处理用户的输入,并判断对错,打分统计正确率。
- 要求能处理用户输入的真分数, 如 1/2, 5/12 等
- 使用 -n 参数控制生成题目的个数,例如执行下面命令将生成10个题目
Myapp.exe -n 10
b.功能设计:
基本满足上述的功能
c.设计实现:
本程序是通过java来实现的,一共有四个类和一个执行类。Fraction类表示分数,RandomGenerator类表示随机生成式子的类;User类表示用户访问类;Calculator类表示计算类。通过new一个User的实例提醒用户输入题数,这个输入函数中实例化一个RandomGenerator对象,生成一个等式。而RandomGenerator类的计算通过Calculator类,内部的参数是Fraction类型的。
d.代码说明:
Fraction类表示的是分数这个类,只有两个属性:分子和分母,重要的函数有:makeItProper():对随机传进参数化简的功能,public Fraction(String trim):还有其中一个构造函数是对传入分数字符串生成一个Fraction实例;RandomGenerator类表示的是随机生成一个式子的类,属性:两个分数、一个结果分数、操作符的下标,操作符的数组,重要函数有:getRandomPara():随机生成一个分数,calResult():计算等式的结果;Calculator类内部都是静态的方法,通过传入两个Fraction类的参数,返回计算后的Fraction;User类属性有:rightNum和totalNum,方法有两个:getCorrectRate()方法和userInput()方法。
具体代码:
Fraction类:
1 package component; 2 3 public class Fraction { 4 private int numerator; 5 private int divisor; 6 7 public Fraction() { 8 super(); 9 } 10 11 public Fraction(int numerator, int divisor) {//构造出对象时就对其进行化简 12 this.numerator = numerator; 13 this.divisor = divisor; 14 makeItProper(); 15 } 16 17 public Fraction(String trim) {//利用正则表达式对其检测,并且分离字符串,生成Fraction对象,考虑分母为0的情况 18 if (trim.trim().matches("0")) { 19 numerator = 0; 20 divisor = Integer.MAX_VALUE; 21 } else if (trim.trim().matches("[0-9]+")) { 22 numerator = Integer.parseInt(trim); 23 divisor = 1; 24 } else if (trim.trim().matches("[0-9]+/[0-9]+")) { 25 String[] result = trim.split("/"); 26 numerator = Integer.parseInt(result[0].trim()); 27 if (Integer.parseInt(result[1].trim()) != 0) 28 divisor = Integer.parseInt(result[1].trim()); 29 else { 30 System.out.println("what you inputed is valid~!"); 31 divisor = Integer.MAX_VALUE; 32 } 33 34 } else { 35 System.out.println("what you inputed is valid~!"); 36 } 37 } 38 39 public int getNumerator() { 40 return numerator; 41 } 42 43 public void setNumerator(int numerator) { 44 this.numerator = numerator; 45 } 46 47 public int getDivisor() { 48 return divisor; 49 } 50 51 public void setDivisor(int divisor) { 52 this.divisor = divisor; 53 } 54 55 public static int commonDivisor(int m, int n) {//计算最大公约数,可以用作化简和通分 56 while (m % n != 0) { 57 int temp = m % n; 58 m = n; 59 n = temp; 60 } 61 return n; 62 } 63 64 public void makeItProper() {//通过计算出的最大公约数进行化简 65 int commondivisor = Fraction.commonDivisor(numerator, divisor); 66 this.numerator = numerator / commondivisor; 67 this.divisor = divisor / commondivisor; 68 } 69 70 @Override 71 public boolean equals(Object obj) {//覆盖equals函数,当且仅当分子和分母都相等,才返回true 72 // TODO Auto-generated method stub 73 if (obj instanceof Fraction) 74 return this.numerator == ((Fraction) obj).numerator && this.divisor == ((Fraction) obj).divisor; 75 return false; 76 } 77 78 @Override 79 public String toString() {//对其格式化输出,唯一特殊的是整数 80 if (numerator % divisor == 0) { 81 return String.format("%d", numerator / divisor); 82 } 83 return numerator + "/" + divisor; 84 } 85 }
RandomGenerator类:
1 package component; 2 3 import java.util.Random; 4 5 public class RandomGenerator { 6 protected Fraction para1; 7 protected Fraction para2; 8 protected Fraction result;//直接计算出结果 9 protected int operator;//通过下标来确定符号 10 protected final String[] operators = { "+", "-", "×", "÷" }; 11 12 public RandomGenerator() {//对分数和计算符号进行随机化 13 para1 = this.getRandomPara(); 14 para2 = this.getRandomPara(); 15 operator = (new Random()).nextInt(4); 16 } 17 18 public Fraction getRandomPara() {//随机分数 19 Random r = new Random(); 20 int m = r.nextInt(20) + 1; 21 int n = r.nextInt(20) + 1; 22 if (r.nextBoolean()) { 23 return new Fraction(m * n, n); 24 } else { 25 while (m > n) { 26 m = r.nextInt(20) + 1; 27 n = r.nextInt(20) + 1; 28 } 29 return new Fraction(m, n); 30 } 31 } 32 33 public Fraction getPara1() { 34 return para1; 35 } 36 37 public void setPara1(Fraction para1) { 38 this.para1 = para1; 39 } 40 41 public Fraction getPara2() { 42 return para2; 43 } 44 45 public void setPara2(Fraction para2) { 46 this.para2 = para2; 47 } 48 49 public Fraction calResult() { 50 switch (operator) { 51 case 0: 52 result = Calculator.addFraction(para1, para2); 53 break; 54 case 1: 55 checkSubValue();//减法考虑结果为负数,如果是,则交换参数 56 result = Calculator.subFraction(para1, para2); 57 break; 58 case 2: 59 result = Calculator.mulFraction(para1, para2); 60 break; 61 case 3: 62 result = Calculator.devideFraction(para1, para2); 63 break; 64 } 65 return result; 66 } 67 68 public void checkSubValue() {//考虑两个数的大小 69 int lcm = (para1.getDivisor() * para2.getDivisor()) 70 / Fraction.commonDivisor(para1.getDivisor(), para2.getDivisor()); 71 int numerator1 = (lcm / para1.getDivisor()) * para1.getNumerator(); 72 int numerator2 = (lcm / para2.getDivisor()) * para2.getNumerator(); 73 if (numerator1 < numerator2) { 74 Fraction temp = new Fraction(para1.getNumerator(), para1.getDivisor()); 75 para1.setNumerator(para2.getNumerator()); 76 para1.setDivisor(para2.getDivisor()); 77 para2.setNumerator(temp.getNumerator()); 78 para2.setDivisor(temp.getDivisor()); 79 } 80 } 81 82 @Override 83 public String toString() { 84 if (operator == 1) { 85 checkSubValue(); 86 } 87 return para1 + " " + operators[operator] + " " + para2 + " = "; 88 } 89 }
Caculator类:
1 package component; 2 3 public class Calculator {//加减乘除的计算,唯一特殊的是減法的結果为0,额外考虑 4 public static Fraction addFraction(Fraction para1, Fraction para2) { 5 int lcm = (para1.getDivisor() * para2.getDivisor()) 6 / Fraction.commonDivisor(para1.getDivisor(), para2.getDivisor()); 7 int numerator1 = (lcm / para1.getDivisor()) * para1.getNumerator(); 8 int numerator2 = (lcm / para2.getDivisor()) * para2.getNumerator(); 9 return new Fraction(numerator1 + numerator2, lcm); 10 } 11 12 public static Fraction subFraction(Fraction para1, Fraction para2) { 13 int lcm = (para1.getDivisor() * para2.getDivisor()) 14 / Fraction.commonDivisor(para1.getDivisor(), para2.getDivisor()); 15 int numerator1 = (lcm / para1.getDivisor()) * para1.getNumerator(); 16 int numerator2 = (lcm / para2.getDivisor()) * para2.getNumerator(); 17 return (numerator1 == numerator2) ? new Fraction("0") : new Fraction(numerator1 - numerator2, lcm); 18 } 19 20 public static Fraction mulFraction(Fraction para1, Fraction para2) { 21 return new Fraction(para1.getNumerator() * para2.getNumerator(), para1.getDivisor() * para2.getDivisor()); 22 } 23 24 public static Fraction devideFraction(Fraction para1, Fraction para2) { 25 return new Fraction(para1.getNumerator() * para2.getDivisor(), para1.getDivisor() * para2.getNumerator()); 26 } 27 }
User类:
1 package component; 2 3 import java.util.Scanner; 4 5 public class User { 6 private int rightNum = 0;//正确的数目 7 private int totalNum = 0;//总数目 8 9 public String getCorrectRate() {//计算正确率 10 if (totalNum == 0)//0的情况特殊,另外输出 11 return "0.0%"; 12 return String.format("%s %.2f %s", "The correct rate is :", (((double) rightNum) / totalNum) * 100, "%"); 13 } 14 15 public void userIntput(String arg) {//用户输入函数,由于输入之前已经检测过,无需再检测 16 Scanner sc = null; 17 String temp; 18 temp = arg.trim(); 19 totalNum = Integer.parseInt(temp); 20 for (int i = 0; i < totalNum; i++) { 21 RandomGenerator rg = new RandomGenerator(); 22 System.out.println("******************************************************"); 23 System.out.print(rg); 24 sc = new Scanner(System.in); 25 if (sc.hasNextLine()) { 26 Fraction result = new Fraction((sc.nextLine())); 27 if (result.equals(rg.calResult())) { 28 this.rightNum++; 29 System.out.println(String.format("%20s", "right!")); 30 } else { 31 System.out.print(String.format("%20s", "false!")); 32 System.out.println(" **the correct answer is:" + rg.calResult()); 33 34 } 35 36 } 37 } 38 System.out.println("******************************************************"); 39 System.out.println( 40 "Finished! The total questions are:" + this.totalNum + ",and the right questions are:" + this.rightNum); 41 System.out.println(this.getCorrectRate()); 42 } 43 44 }
执行类:
1 package component; 2 3 public class GeneratorTester { 4 public static void main(String[] args) {//对输入参数提示和限制 5 User u = new User(); 6 String num = null; 7 if (args.length > 0) { 8 if (args[0].trim().equals("-n") && args.length == 2 && args[1].matches("[0-9]+")) { 9 num = args[1]; 10 u.userIntput(num); 11 } else 12 System.out.println("Parameter formating valid! The standard format is -n digital"); 13 } else { 14 System.out.println("No defined parameter"); 15 } 16 } 17 }
e.测试运行:
1.首先对控制台输入的时候 进行参数检测:
2.对用户的输入的结果进行检测
PSP表:
PSP2.1 | Personal Software Process Stages | Time (%) Senior Student | Time (%) |
Planning | 计划 | 8min | 10min |
· Estimate | 估计这个任务需要多少时间 | 2min | 2min |
Development | 开发 | ? | ? |
· Analysis | 需求分析 (包括学习新技术) | 3min | 10min |
· Design Spec | 生成设计文档 | 5min | 6min |
· Design Review | 设计复审 | 10min | 15min |
· Coding Standard | 代码规范 | ? | ? |
· Design | 具体设计 | 15min | 20min |
· Coding | 具体编码 | 1h | 3h |
· Code Review | 代码复审 | 15min | 20min |
· Test | 测试(自我测试,修改代码,提交修改) | 13min | 21min |
Reporting | 报告 | 1h | 1.2h |
· | 测试报告 | 5min | 5min |
· | 计算工作量 | 10min | 8min |
· | 并提出过程改进计划 | 5min | 5min |
小结:
这次作业难度不高,但是也花费了我挺久的时间,主要是我没有对这个题目进行全面的认识,而且没有好好规划,所以造成了“超时”完工。虽然题目很简单,但是在思考过程中还是得考虑很多东西,比如说分母不为0的问题,减法减出分数的控制问题,覆盖Fraction的equals()问题等等。不过“阿超”完成这个程序的速度也太快了吧,20分钟?看来我的经验还是有很多不足。还有就是拓展性的问题,就以Java来说,设计好类与类之间的关系十分重要,对你的维护以及功能拓展有很大的便捷,不然就十分有可能重新设计,导致工作量增加。所以我觉得可以去看一些关于程序设计的书。至于本程序的扩展,我暂时考虑到的是多项的扩展,因为RandomGenerator类是一个等式,如果要增加项数的话,可以考虑再写一个类Decorator,它和RandomGenerator一起继承一个抽象类,假设是Component,这个类有两个属性,String description 和 Fraction result,表示它的式子和最后的结果,抽象方法有getDecription()和getResult();而Decorator类中有Component引用属性,假设是obj,当要实现抽象类的方法时,getResult()返回的是obj.CalReult()与Decorator类的Fraction引用属性的计算值,至于符号就随机生成,这样当new Decorator(obj)时,getResult()可以得到新的结果,同理getDescription(),至于实现,其实没有这么简单,还要考虑随机生成的问题,以及Decorator类这个新生成后缀的符号和obj内符号之间优先级的问题,总之还是要注意很多的。
2017-03-02 15:24:38