• 结对项目(四则运算式子生成器)


    成员:林跃玲(3218005082)、罗艺明(3118005066)

    1、GitHub地址https://github.com/HandsomeLuoYM/examination-system


    2、PSP表格

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

    3、效能分析

    当我随机生成10000条运算式时:可以看到堆内存消耗在上升后趋于稳定

    在监控中可见,类的利用率算高,且CUP的利用率并不高,但是对于内存的消耗在短时间达到很高

    从下面报表中看出类的消耗,由于计算中大量使用字符串的加减,故为减轻虚拟机的负担,我们使用StringBuilder来进行大部分的字符串操作


    4、设计实现过程


    首先确定编程语言,为了减低学习成本,使用比较熟悉的Java进行相关的开发,需求中涉及到随机生成并且校对,故需要大量操作字符串,故使用StringBuilder来进行相应的操作,提升系统的速度,其次还涉及相关的文件操作,故需要使用到IO流及相关操作,同时为了让用户有更好的交互性,还需使用到 Java 提供的 Swing 界面,最后由于需要分析效能,故需要使用到相应的性能分析神器 JProfiler。


    相关类分析
    • CreatUtil类:创建运算相关操作
      • creat方法:随机生成式子
      • creatNum方法:随机生成操作数
      • creatSign方法:随机生成符号
      • formulaNum方法:设定随机生成一定数目的式子
      • numRange方法:判断操作数是否超过最大值
    • ProcessUtil类:计算过程的相关方法
      • creatNum方法:将答案按规范生成出来
      • gcd方法:求两数的最大公因数
      • charFind方法:存储指定字符的位序式子
      • changeNum方法:将数字字符串转为数字值
      • judge方法:判断式子是否符合规范
      • change方法:将字符串的操作数分子分母转成数字
    • CalculateUtil类:计算方法
      • add方法:加法运算
      • minus方法:减法运算
      • multiply方法:乘法运算
      • divide方法:除法运算
      • calculate方法:对运算符号左右的两个数进行运算
      • calculateFormula方法:计算式子
    • CheckUtil类:校验式子(查重)
      • spiltStringBuilderToArray方法:将式子拆分普通数组
      • spiltStringBuilderToList方法:将式子拆分成List数组
      • spiltStringBuilderToOrderList方法:将式子拆分成有序的 List 数组
      • judgeRepeat方法:判断内容是否有重复
    • FileDao方法:
      • storageResult方法:将结果存储到文件中
      • storageFile方法:存储过程式子和答案
      • readFile方法:读取文件
    • Operator枚举:对运算符相关信息进行封装,避免多次的 new 减低效能
    • MainUI类:用户交互的主页面
    • UserUI类:用户填写等相关操作的页面


    5、代码说明

    以下列举了关键代码以及说明
    • CreatUtil类:在改类中采用了较多的随机生成数来实现相对随机,同时在每一步都有进行必要的数据校验,以保证数据的准确度。
        @SuppressWarnings("all")
        public class CreatUtil {
    
        //日志输出
        private static final Logger logger = Logger.getLogger("CreatUtil");
        List<StringBuilder> formula;
        //备份式子,存储"分子/分母"结构的式子,便于结果计算
        List<StringBuilder> answer;
        StringBuilder extraCopy ;
    
        public List<StringBuilder> getFormula() {
            return formula;
        }
    
        public List<StringBuilder> getAnswer() {
            return answer;
        }
    
        /**
         * 随机生成式子
         * 用List存储式子
         * @param maxNum 最大值
         * @return 返回改字符串
         * */
        public StringBuilder creat(int maxNum) {
            StringBuilder formula = new StringBuilder();
            extraCopy = new StringBuilder(" ");
            //符号个数 (1,2,3)
            int signNum = (int)(Math.random()*3+1);
            creatNum(formula,maxNum);
            for(int i=0; i<signNum; i++) {
                creatSign(formula);
                creatNum(formula,maxNum);
            }
            formula.append(Operator.EQUAL_SIGN.getExpress() +" ");
            return formula;
        }
    
        /**
         * 随机生成操作数
         * 并将操作数存入list中
         * @param formula 字符串
         * @param maxNum 数
         * @return 返回参数的字符串
         * */
        public StringBuilder creatNum(StringBuilder formula,int maxNum) {
        	int numerator,denominator,type;
    		type = (int)(Math.random()*2);
            //生成整数
    		if(type==0) {
    			do {
    				numerator =(int)(Math.random()*10);
    			}while(numerator > maxNum);
                //备份分子/分母
    			extraCopy.append(numerator+"/"+1+" ");
    			formula.append(numerator+" ");
    		}
    		else {
    			do {
                    //随机生成分子
    				numerator = (int)(Math.random()*10);
                    //保证分母不等于0
    				while((denominator=(int)(Math.random()*10))==0);
    			}while(!numRange(numerator, denominator,maxNum));
                //备份分子/分母
    			extraCopy.append(numerator+"/"+denominator+" ");
    			formula.append(ProcessUtil.creatNum(numerator, denominator));
    		}
    		return formula;
        }
    
        /**
         *  随机生成符号
         * 并将符号存入list中
         * @param formula 符号
         * @return 返回符号
         */
        public StringBuilder creatSign(StringBuilder formula) {
            //符号类型(+ - * /)
            int signType = (int)(Math.random()*4+1);
            switch (signType){
                case 1 :
                    formula.append(Operator.PLUS_SIGN.getExpress());
                    extraCopy.append(Operator.PLUS_SIGN.getExpress());
                    break;
                case 2 :
                    formula.append(Operator.MINUS_SIGN.getExpress());
                    extraCopy.append(Operator.MINUS_SIGN.getExpress());
                    break;
                case 3 :
                    formula.append(Operator.MULTIPLIED_SIGN.getExpress());
                    extraCopy.append(Operator.MULTIPLIED_SIGN.getExpress());
                    break;
                case 4 :
                    formula.append(Operator.DIVISION_SIGN.getExpress());
                    extraCopy.append(Operator.DIVISION_SIGN.getExpress());
                    break;
                default:
    
            }
            extraCopy.append(" ");
            formula.append(" ");
            return formula;
        }
    
        /**
         * 设定随机生成一定数目的式子,并将式子和答案分别存在formula和answer中
         * @param num 生成的式子数目
         * @param maxNum 最大值
         */
        public void formulaNum(int num, int maxNum) throws IOException {
            Long beginTime = System.currentTimeMillis();
            //存放拆分完的式子
            List<List<String>> formulaLists = new ArrayList<List<String>>(num);
            formula = new ArrayList<StringBuilder>();
            answer = new ArrayList<StringBuilder>();
            //原始式子
            StringBuilder singleFormula;
            for(int i=0; formula.size()<num; i++) {
                formula.add(singleFormula = creat(maxNum));
                CalculateUtil.calculateFormula(extraCopy);
                //式子不符合规范(结果为负数),并且查重
                if(extraCopy.charAt(0)=='@' || CheckUtil.judgeRepeat(singleFormula,formulaLists,extraCopy,answer)) {
                    formula.remove(formula.size()-1);
                    continue;
                }
                answer.add(extraCopy);
            }
            int i=0;
            FileDao.storageFile(formula,"Exercises.txt");
            FileDao.storageFile(answer,"Answers.txt");
            System.out.println("生成时间: " + (System.currentTimeMillis()-beginTime));
        }
    
        /**
         * 设定操作数的最大数值
         * @param numerator 分子
         * @param denominator 分母
         * @param maxNum 最大值
         * @return 是否超过最大值
         */
        public boolean numRange(int numerator, int denominator,int maxNum) {
            if((numerator/denominator)<maxNum) {
                return true;
            }else if((numerator/denominator)==maxNum) {
                if((numerator%denominator)==0) {
                    return true;
                }
            }
            return false;
        }
    }
    
    
    • CheckUtil类:对式子的生成进行校验,将式子进行拆分,然后进行比较,并且也对答案进行比较,双重保证了式子的唯一性
    
    @SuppressWarnings("all")
    public class CheckUtil {
    
        /**
         * 将StringBuilder拆分成string数组
         * @param stringBuilder
         * @return 返回string[] 数组
         */
        public static String[] spiltStringBuilderToArray(StringBuilder stringBuilder){
            return stringBuilder.toString().split("\s+");
        }
    
        /**
         * 将StringBuilder拆分成List数组
         * @param stringBuilder string串串
         * @return 返回List数组
         */
        public static List<String> spiltStringBuilderToList(StringBuilder stringBuilder){
            return Arrays.asList(spiltStringBuilderToArray(stringBuilder));
        }
    
        /**
         * 将StringBuilder拆分成有序的 List 数组
         * @param stringBuilder string串串
         * @return 返回List数组
         */
        public static List<String> spiltStringBuilderToOrderList(StringBuilder stringBuilder){
            List<String> stringList = spiltStringBuilderToList(stringBuilder);
            Collections.sort(stringList);
            return stringList;
        }
    
        /**
         * 判断内容是否有重复
         * @param formula 判断的式子
         * @param lists 排序完的全部 list
         * @param answer 答案
         * @param answerLists 答案集
         * @return 返回是否重复
         */
        public static boolean judgeRepeat(StringBuilder formula, List<List<String>> lists,StringBuilder answer,List<StringBuilder> answerLists){
            List<String> formulaList = spiltStringBuilderToOrderList(formula);
            int i;
            for (i = 0;i<lists.size();i++){
                if(lists.get(i).equals(formulaList) && answer.toString().equals(answerLists.get(i).toString())){
                    return true;
                }
            }
            lists.add(formulaList);
            return false;
        }
    }
    
    
    • CalculateUtil类:讲计算方法进行抽离,减低耦合度,也有进行数据的判断,保证了系统的健壮性
    
    @SuppressWarnings("unused")
    public class CalculateUtil {
    
    	private static final Logger logger = Logger.getLogger("CalculateUtil");
    
    	/**
    	 * 加法运算
    	 * @param numerator1 分子1
    	 * @param denominator1 分母1
    	 * @param numerator2 分子2
    	 * @param denominator2 分母2
    	 * @return 返回结果
    	 */
    	public static StringBuilder add(int numerator1,int denominator1,int numerator2,int denominator2) {
    		int numerator,denominator;
    		StringBuilder result = new StringBuilder();
    		numerator = numerator1*denominator2+numerator2*denominator1;
    		denominator = denominator1 * denominator2;
    		if(numerator!=0) {
    			//化简分子分母(除以最大公因数)
    			int gcdNum = ProcessUtil.gcd(numerator,denominator);
    			numerator /= gcdNum;
    			denominator /= gcdNum;
    		}
    
    		result.append(numerator+"/"+denominator);
    		return result;
    	}
    
    	/**
    	 * 减法运算
    	 * @param numerator1 分子1
    	 * @param denominator1 分母1
    	 * @param numerator2 分子2
    	 * @param denominator2 分母2
    	 * @return 返回计算结果
    	 */
    	public static StringBuilder minus(int numerator1,int denominator1,int numerator2,int denominator2) {
    		int numerator,denominator;
    		StringBuilder result = new StringBuilder();
    
    		numerator = numerator1*denominator2-numerator2*denominator1;
    		denominator = denominator1*denominator2;
    		//化简分子分母(除以最大公因数)
    		if(numerator!=0) {
    			int gcdNum = ProcessUtil.gcd(numerator,denominator);
    			numerator /= gcdNum;
    			denominator /= gcdNum;
    		}
    		result.append(numerator+"/"+denominator);
    		return result;
    	}
    
    	/**
    	 * 乘法运算
    	 * @param numerator1 分子1
    	 * @param denominator1 分母1
    	 * @param numerator2 分子2
    	 * @param denominator2 分母2
    	 * @return 返回计算结果
    	 */
    	public static StringBuilder multiply(int numerator1,int denominator1,int numerator2,int denominator2) {
    		int numerator,denominator;
    		StringBuilder result = new StringBuilder();
    		//操作数有一个等于0的情况
    		if(numerator1==0||numerator2==0) {
    			result.append(0+"/"+1);
    		}
    		//操作数大于0的情况
    		else {
    			numerator = numerator1*numerator2;
    			denominator = denominator1*denominator2;
    			//化简分子分母(除以最大公因数)
    			if(numerator!=0) {
    				int gcdNum = ProcessUtil.gcd(numerator,denominator);
    				numerator /= gcdNum;
    				denominator /= gcdNum;
    			}
    			result.append(numerator+"/"+denominator);
    		}
    		return result;
    	}
    
    	/**
    	 * 除法运算
    	 * @param numerator1 分子1
    	 * @param denominator1 分母1
    	 * @param numerator2 分子2
    	 * @param denominator2 分母2
    	 * @return 返回计算结果
    	 */
    	public static StringBuilder divide(int numerator1,int denominator1,int numerator2,int denominator2) {
    		int numerator,denominator;
    		StringBuilder result = new StringBuilder();
    		numerator = numerator1*denominator2;
    		denominator = denominator1*numerator2;
    		//化简分子分母(除以最大公因数)
    		if(numerator!=0) {
    			int gcdNum = ProcessUtil.gcd(numerator,denominator);
    			numerator /= gcdNum;
    			denominator /= gcdNum;
    		}
    		result.append(numerator+"/"+denominator);
    		return result;
    	}
    
    	/**
    	 * 对运算符号左右的两个数进行运算
    	 * @param index 运算符的位序
    	 * @param extraCopy 待计算的式子
    	 * @return
    	 */
    	public static StringBuilder calculate(int index,StringBuilder extraCopy) {
    		char sign = extraCopy.charAt(index);
    		int beginIndex = 0, endIndex = -1;
    		int[] datas = new int[3];
    		for(int index1=0; ; beginIndex=index1) {
    			//找到第一个操作数的开头空格
    			index1 = extraCopy.indexOf(" ", index1+1);
    			if(index1==(index-1)) {
    				break;
    			}
    		}
    		datas = ProcessUtil.change(extraCopy, beginIndex);
    		int numerator1 = datas[1];
    		int denominator1 = datas[2];
    		datas = new int[3];
    		datas = ProcessUtil.change(extraCopy, index+1);
    		int numerator2 = datas[1];
    		int denominator2 = datas[2];
    		endIndex = datas[0];
    		//删除数字部分
    		extraCopy.delete(beginIndex+1,endIndex);
    		//根据符号进行相应的运算
    		switch(sign){
    			case '+':
    				extraCopy.insert(beginIndex+1, add(numerator1,denominator1,numerator2,denominator2));
    				break;
    			case '-':
    				if(!ProcessUtil.judge(numerator1, denominator1, numerator2, denominator2)) {
    					//识别答案是否为负数
    					extraCopy.insert(0, "@ ");
    					break;
    				}
    				else{
    					extraCopy.insert(beginIndex+1, minus(numerator1,denominator1,numerator2,denominator2));
    					break;
    				}
    			case '*':
    				extraCopy.insert(beginIndex+1, multiply(numerator1,denominator1,numerator2,denominator2));
    				break;
    			case '÷':
    				if(numerator2 == 0) {
    					//识别答案是否为负数,是的话在开头插入@作为标识
    					extraCopy.insert(0, "@ ");
    					break;
    				}
    				else{
    					extraCopy.insert(beginIndex+1, divide(numerator1,denominator1,numerator2,denominator2));
    					break;
    				}
    			default: break;
    		}
    		return extraCopy;
    	}
    
    	/**
    	 * 按优先级进行运算(*  /  +  -)
    	 * @param extraCopy copy副本
    	 * @return 返回
    	 */
    	public static StringBuilder calculateFormula(StringBuilder extraCopy) {
    //		logger.info(extraCopy.toString());
    		//记录符号的位序
    		int index = -1;
    		//计算式子
    		Pattern pattern1 = Pattern.compile("[*]|[÷]");
    		Matcher m1;
    		while((m1 = pattern1.matcher(extraCopy)).find()) {
    			index = m1.start();
    			calculate(index, extraCopy);
    			if(extraCopy.charAt(0)=='@') {
    				break;
    			}	
    		}
    		//如果式子正确,在进行加运算(从左到右)
    		if(extraCopy.charAt(0)!='@') {
    			Pattern pattern2 = Pattern.compile("[-]|[+]");
    			Matcher m2;
    			while((m2 = pattern2.matcher(extraCopy)).find()) {
    				index = m2.start();
    				calculate(index, extraCopy);
    				if(extraCopy.charAt(0)=='@') {
    					break;
    				}	
    			}
    		}
    		//如果运算结束后(式子正确),调整答案格式
    		if(extraCopy.charAt(0)!='@') {
    			int datas[] = new int[3];
    			datas = ProcessUtil.change(extraCopy, 0);
    			int numerator = datas[1];
    			int denominator = datas[2];
    			//将原存储内容清空
    			extraCopy.setLength(0);
    			//将答案换成标准格式
    			extraCopy.append(ProcessUtil.creatNum(numerator, denominator));
    		}
    		return extraCopy;
    	}
    }
    
    
    • ProcessUtil类:提供了计算过程中的一下而操作方法,为计算提供了坚实的后盾
    
    public class ProcessUtil {
    
        /**
         * 将答案按规范生成出来
         * @param numerator 分子
         * @param denominator 分母
         * @return 式子
         */
        public static StringBuilder creatNum(int numerator, int denominator) {
            StringBuilder num = new StringBuilder();
            int gcdNum = gcd(numerator, denominator);
            numerator /= gcdNum;
            denominator /= gcdNum;
            if (numerator >= denominator) {
                //分子大于等于分母
                if (numerator % denominator == 0) {
                    //结果为整数
                    num.append(numerator / denominator + " ");
                } else {
                    //结果为带分数
                    int interger = numerator / denominator;
                    numerator = numerator - (interger * denominator);
                    num.append(interger + "’" + numerator + "/" + denominator + " ");
                }
            } else {
                //分子小于分母
                if (numerator == 0) {
                    //分子小于0
                    num.append(0 + " ");
                } else {
                    //其他情况
                    num.append(numerator + "/" + denominator + " ");
                }
            }
            return num;
        }
    
        /**
         * 求两数的最大公因数
         * @param num01 数字1
         * @param num02 数字2
         * @return 返回公因数
         */
        public static int gcd(int num01, int num02) {
            int num = 0;
            while (num02 != 0) {
                num = num01 % num02;
                num01 = num02;
                num02 = num;
            }
            return num01;
        }
    
        /**
         * 将式子中指定字符的所有位序存储起来
         * @param str 字符串
         * @param formula 式子
         * @return 返回位序
         */
        public static int[] charFind(String str, StringBuilder formula) {
            int[] indexs = new int[20];
            for (int i = 0; ; i++) {
                if (i == 0) {
                    indexs[i] = formula.indexOf(str, 0);
                    continue;
                }
                if (str.equals(" ") && (indexs[i - 1] == formula.length() - 1)) {
                    break;
                }
                if (str.equals(" ") || str.equals("/")) {
                    indexs[i] = formula.indexOf(str, indexs[i - 1] + 1);
                }
                if (str.equals("/") && (formula.length() - 1 - indexs[i] <= 4)) {
                    break;
                }
            }
            return indexs;
        }
    
    
        /**
         * 将指定数字字符串转为数字值
         * @param formula 带查找的式子
         * @param fromIndex 操作数前的空格位序
         * @param endIndex 操作数后的空格位序
         * @return 返回数字
         */
        public static int changeNum(StringBuilder formula, int fromIndex, int endIndex) {
            int num = -1;
            //根据数字的位数进行转换
            int sum = 0, temp;
            for (int i = 1; i < (endIndex - fromIndex); i++) {
                temp = (int) Math.pow((double) 10, (double) (i - 1));
                num = (int) (formula.charAt(endIndex - i) - 48) * temp;
                sum += num;
            }
            return sum;
        }
    
        /**
         * 判断被减数、减数是否符合规范(true:符合;false:不符合)
         * @param numerator1 第一个操作数的分子
         * @param denominator1  第一个操作数的分母
         * @param numerator2 第二个操作数的分子
         * @param denominator2 第二个操作数的分母
         * @return 返回是否正确
         */
        public static boolean judge(int numerator1, int denominator1, int numerator2, int denominator2) {
            int numerator = numerator1 * denominator2 - numerator2 * denominator1;
            if (numerator < 0) {
                return false;
            }
            return true;
        }
    
    
    
        /**
         * 通过字符串将操作数的分子分母转成数字
         * @param extraCopy 进行操作的字符串
         * @param beginIndex 操作数前的空格位序
         * @return 返回数字集
         */
        public static int[] change(StringBuilder extraCopy, int beginIndex) {
    		int[] num = new int[3];
    		int[] blanks = charFind(" ", extraCopy);//存储空格的位序,方便找到完整的操作数
    		int indexBl = -1 ,indexBa ;
    		indexBa = extraCopy.indexOf("/", beginIndex);//反斜杠的位置
    		for(int i=0; i<blanks.length; i++) {
    			if(blanks[i]==beginIndex) {//找到传入空格位序在blanks中的位置
    				indexBl = i;
    				break;
    			}
    		}
    		num[0]=blanks[indexBl+1];//操作数后的空格位序
    		num[1]=changeNum(extraCopy,beginIndex,indexBa);//分子
    		num[2]=changeNum(extraCopy,indexBa,num[0]);//分母
    		return num;
    	}
    }
    
    
    • FileDao类:对文件的导入和导出进行封装,也就是进行数据持久化操作,方法中有对于文件格式等进行相应的判断,杜绝了一些异常的出现
    
    public class FileDao {
    
        private static final String PATH = System.getProperty("user.dir");
    
        /**
         * 输出信息导文件中
         * @param list 输入的内容
         * @param fileName 输入的文件名
         * @return 返回是否成功
         */
        public static boolean storageFile(List<StringBuilder> list, String fileName)  {
            File file = new File(PATH + "\" +fileName);
            FileOutputStream fileOutputStream = null;
            try {
                fileOutputStream = new FileOutputStream(file,false);
                String content = "";
                for (int i =0 ;i<list.size();i++){
                    content = content + (i+1) + "、" + list.get(i).toString() + "
    ";
                }
                fileOutputStream.write(content.getBytes());
            } catch (IOException e) {
                e.printStackTrace();
                return false;
            }finally {
                try {
                    fileOutputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            return true;
        }
    
        /**
         * 阅读用户传入的文件
         * @param file 传入的文件
         * @return 返回一个List集合
         */
        public static List<StringBuilder> readFile(File file) {
            List<StringBuilder> list = new ArrayList<>();
            FileInputStream fileInputStream = null;
            BufferedReader bufferedReader = null;
            //判断文件类型是否正确
            if (!file.exists() || !file.getName().contains("txt")){
                return null;
            }
            try {
                fileInputStream = new FileInputStream(file);
                bufferedReader = new BufferedReader(new InputStreamReader(fileInputStream));
                String raw;
                for (int i = 0; null != (raw = bufferedReader.readLine()); i++) {
                    //文件内容是否有、,分情况输出
                    if (raw.contains("、")) {
                        list.add(new StringBuilder(raw.substring(raw.indexOf("、") + 1, raw.length() - 1)));
                    } else {
                        list.add(new StringBuilder(raw));
                    }
                }
            }catch (IOException e){
                e.printStackTrace();
            }finally {
                try {
                    fileInputStream.close();
                    bufferedReader.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            return list;
        }
    }
    
    
    • Operator枚举:对操作符进行简单的封装
    
    public enum Operator {
    
        /**
         * 运算符
         */
        PLUS_SIGN("加号","+","+"),
        MINUS_SIGN("减号","-","-"),
        MULTIPLIED_SIGN("乘以号","*","*"),
        DIVISION_SIGN("除以号","÷","/"),
        EQUAL_SIGN("等于号","=","=");
    
        private String name;
        private String express;
        private String calculation;
    
        Operator(String name, String express, String calculation) {
            this.name = name;
            this.express = express;
            this.calculation = calculation;
        }
    
        public String getName() {
            return name;
        }
        public String getExpress() {
            return express;
        }
        public String getCalculation() {
            return calculation;
        }
    }
    
    

    6、测试运行


    • 该程序支持直接生成式子,如果选择不导入文件,则系统自动生成式子,程序支持 1W 条或更高数量的式子生成,也会将式子生成文件存储起来


    • 系统10000道题目的生成测试


    • 该程序支持本地文件导入,并且对文件的绝对路径有判错功能,当绝对路径出错时,会显示红框提示,也支持传入文件的判错功能


    • 同时程序还支持校对功能,并会将校对的结果存入相应文件中


    • 本系统有自带的操作说明,用户可通过操作说明了解本系统。


    • 本系统有许多判错功能。本系统仅支持10以内的操作数运算,若输入最大操作数大于10,会提示错误;在该页面未填写完整,无法跳转或者点击下一页;若输入跳转页面大于总页面,会有提示错误提示


    7、项目小结

    项目过程:
    • 初期:由于没有很好的规划好架构,也缺少了一些必要的交流,导致后期项目的开发受阻。
    • 中期:在编程过程中,没有较好的分包,造成了业务层没有完全抽离出来。
    • 后期:在测试的调试中,遇到 BUG 由于没有较好的前期规划,在解决 BUG 时比较困难。
    个人总结:
    • 罗艺明:由于前期的繁忙,没有第一时间加入到项目的开发中。而在开发中存在一些不可忽视的问题,像没有实现用户交互和业务逻辑的完全分离,另一方面为分包没有很规范,最后就是在合作中缺少一些交流。合作伙伴林跃玲同学发现了很多闪光点,她对于开发充满积极性,不会推脱,并且对新知识的学习速度较块。但是编程能力有待提升。
    • 林跃玲:本次项目我没有提前做好完整需求分析,就是边写边做,所以在后面写接口的时候很混乱,经常改来改去。既浪费时间,有写出了很多bug。还有就是我写项目的结构以及思路比较混乱,给队友带来了较大不便,这是我本次项目体现出来的两个比较大的问题。从罗艺明同学身上,我学到了一些写项目的小经验,也让我认识到我写项目的很多不足之处,以后得多多找他请教请教。
  • 相关阅读:
    机器学习:贝叶斯分类器(一)——朴素贝叶斯分类器
    机器学习:kNN算法(二)—— 实战:改进约会网站的配对效果
    机器学习:kNN算法(一)—— 原理与代码实现(不调用库)
    Oracle给表设置自增字段
    IMAP、POP3、SMTP邮件服务器
    网站高并发大流量访问的10个处理及解决方案
    浅谈async/await
    【前端】加载的图片太多或者太大优化方案(上)
    【前端】本地调试H5页面方案总结
    alphafold2_conda版安装
  • 原文地址:https://www.cnblogs.com/gdutming/p/12616850.html
Copyright © 2020-2023  润新知