项目源码: https://git.coding.net/beijl695/EGener2.git

(代码纯属原创,设计细节不同,请思量)

项目发布后,由于期间各种事情,耽搁至最后一天交付。这次的项目是由我和邵汝佳同学共同完成,感谢partner!

成员:

贝金林(我)    2016012070

 邵汝佳             2016012085
psp:

PSP阶段

预计用时(分)

实际用时(分)

计划

5

5

估计这个任务需要的时间

5

5

开发

60 * 24

60 * 68

需求分析

45

11

生成设计文档

45

42

设计复审

30

1.5 * 60

代码规范

10

20

具体设计

60 * 2

60 * 4

具体编码

60 * 12

60 * 50

代码复审

60 * 3

60 * 5

测试

60 * 5

60 * 6

报告

60 * 2.5

60 * 7

测试报告

60

60 * 2

计算工作量

30

60

总结

60

60 * 4

设计:

这些都是面向对象程序设计的基本要求,汗!信息隐藏是类设计的基本要求,只暴露需要暴露的接口和域。接口设计来源于需求,我们在分析需求后进行初步设计,在初步设计时大致地细化类,每个类分别具有一定地功能,并暴露出接口(公共方法)。

这个项目比较简单,但是期间有很多麻烦的事情,比如说单元测试和效能分析。个人认为这些对这个小项目没什么影响,除非将这个小项目一直拓展。

这个项目开始之初,我们对项目进行了需求分析和初步设计。

需求分析几乎是照抄“客户需求”:

  

初步设计:

  

然而,做完了这些,具体设计几乎是边设计边写程序了,也就是说我们没有提前进行具体设计。

核心的代码虽然想直接使用上次项目的现成类(包括继承),但是因为需求的变化以及上次项目类的设计还不够仔细,故无可避免地要对现有类进行修改所以就干脆重写代码。对了,这次使用的项目是我做的EGener,它是java编写的命令行程序,在它的类库有我们所需的类,如LeftGenerator,EquationGenerator这两个类。

基于“工厂”设计,我们将等式左边(Left)比作原料,通过左式生成器(LeftGenerator)生成原料,将等式生成器(EquationGenerator)比作工厂,生成完整等式(产品)。

以下列出了类库中的所有类:

这里的类都是后台的核心类,Command就是项目规定的计算模块,可以通过命令行运行;Range是我们设计用来判断是否满足数字上下界的一个类;Test是我们用来做单元测试的主类,我们把单元测试做的比较灵活,我们的单元测试在某些类不能达到90% ,但是对于一些简单类,我们尽量给予保证。

单元测试截图:

可看到简单类(实现某单一功能)的覆盖率达到了百分之九十以上。

关于性能改进:

主要是对于计算模块(Command)。起初,左式生成器生成的左式真的是随机,它的目的就是随机生成运算数,运算符,随机拼接括号(用正则匹配适当位置,随机在“数符数”添加一重括号);重点是等式生成器,它具有计算,判断,生成的功能。我在等式生成器内部构建了左式生成器,等式生成器的next()方法一定会生成符合条件的等式,因为它在获取结果的过程中,会进行判断。若是出现问题,如生成的中间结果不在Range内,就会调用左式生成器的next()令左式生成器继续生成新等式,再进行运算和判断。(ps:next方法是由random的next产生灵感)

后来在进行测试时,发现运算符多,运算带乘除,数的下界高,上界低都会使程序变慢,因为这些因素都会导致左式回炉的几率高。而我们程序的性能就是由回炉的次数决定的。这时我们意识到不能完全随机,于是我们开始修改LeftGenerator来使它能生产出更容易满足条件的原料。if(rand.nextInt(10) < 3)表示百分之三十的几率产生.....我们经常用这种形式设置随机的概率。我们还发现31以上1000内无乘除,于是就避免了更多垃圾左式的产生。

虽然开始时我们决定在产生带乘除的题目时,一定会带至少一个乘除号。但当31以上时,程序出现死循环;运算符10个,生成1000道带乘除的题,而下界接近于30时,也很难生成。所以我们去掉了一定生成乘除的功能,改为高概率生成一个乘除,低概率生成乘除。

另外,乘除的算数也是决定性能的重要部分,在31以上无乘除;在给定范围内,若有可能,我们高几率生成31以内数字作为算子,使之更容易生成合法的带乘除左式。

我们对于性能的改进比较粗糙,主要由“不可用”改为“可用”我们就很满足了,

1,在Command模块初步实现时,对于生成“1000道[30,1000],最多10个运算符,带乘除,带括号”的题库,程序运行特慢,一分钟生成一道题,乘除算子只有30和31。通过将“一定生成乘除”改为“大数低几率”的方式生成乘除,这个问题解决了。花时60minutes。

2,虽然解决了主要因数(乘除的产生),但是程序还是不够快,有时一道题要花几秒产生。于是我们再从其他因素着手,对程序进行改进,还是在改进左式(原料),使之生成合理的运算数,使之生成合理的符号等。花时60 * 3minutes。

基于时间成本,我们的性能测试比较粗糙,也许不做精细的性能测试会提高成本,但在实际开发中心理上却很想偷懒。

关于异常处理方法:

异常处理使得程序的正常运行与处理方式分开,通过抛出异常使之能在恰当的地方进行处理。考虑到时间成本,我们并没有设计专用的异常类,因为我们的程序只有两个模块(计算模块和UI)。产生异常的模块若是计算模块,我们再产生异常的地方抛出带有“提示语句”的Exception,使得计算的线程能够中断,抛到UI模块进行处理(显示Dialog打印错误信息)。而UI模块产生的异常直接处理。

Command中:

UI中:

软件运行时:

以上只列出了三种不同的异常(我们的异常由打印的消息来区分),除了这些还有“文件上传失败异常”和“题库解析失败异常”等异常。

界面模块的设计:

界面模块的设计很简陋,由于不会使用图形化操作插件本人最烦GUI的布局。

出题器布局如下:

答题器布局如下:

UI的设计主要由一个主框架,一个菜单,数个对话框和两个面板构成,出题面板的设计思路比较简单:获取参数,出题并导出至文件,回显。

//为“出题”添加监听器
void addListenerInGener() {
generB.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
System.out.println("aadfdasfdasfasd");
num = numF.getText();
oNum = operF.getText();
down = rangeDownF.getText();
up = rangeUpF.getText();
isWithBrackets = isWithBracketsC.getState();
isWithMD = isWithMDC.getState();
StringBuilder sb = new StringBuilder();
sb.append("-n " + num + " -m " + down + " " + up + " -o " + oNum);
if(isWithBrackets) {
sb.append(" -b");
}
if(isWithMD) {
sb.append(" -c");
}
String[] args = sb.toString().split(" ");
BufferedReader bf;
try {
//调用 Command出题
Command.main(args);
//回显到TextArea
File file = new File(".." + File.separator + "result.txt");
bf = new BufferedReader(
new FileReader(file));
String line = "";
generT.setText("");
while((line = bf.readLine()) != null) {
generT.append(line);
generT.append("\n\r");
}
remindL.setText("已将题目导出至" + file.getCanonicalPath());
remindDia.setVisible(true);
bf.close();
} catch(Exception ex) {
String errMsg = ex.getMessage();
errL.setText(errMsg);
errDia.setVisible(true);
System.out.println("massage:" + errMsg);
}
}
});

答题器的思路:通过FileDialog获取txt文本,同时导入Exam的对象中,Exam的对象是专门为答题器设计的。Exam会读取文本文件(若文件内容不符合则抛出异常),并将文件的题目进行解析和优化(去空格和等号),调用内置的等式生成器产生结果,并将题目和答案存入映射集合中(同时起到去重作用)。Exam的对象暴露了许多接口,如获取答题的时间,答对的题数等等。因为Exam模块由于是提前做的,所以可能一些接口没有用上,留着以后用吧。Exam对象导入题目后,用户可点击“开始答题”进行答题。在UI中,我们设计了三个方法来控制出题:beginExam,check 和endExam,它们分别用来控制出题,验算和结束答题的行为。

void beginExam() {
String question;
if((question = exam.next()) == null) {
endExam();
return;
}
questionL.setText(question);
answerT.setText(null);
examD.setVisible(true);
}
void check() {
String answer = answerT.getText();
boolean isCorrect = false;
isCorrect = exam.isCorrect(answer);
if(isCorrect) {
checkL.setText("恭喜你,答对了!");
}
else {
checkL.setText("很遗憾,答错了," + exam.getQuestion() + "=" + exam.getAnswer());
}
examD.setVisible(false);
checkD.setVisible(true);
}
void endExam() {
exam.end();
String result = "已回答" + exam.getNumOfDone() + "题," + "共答对"
+ exam.getNumOfRight() + "题,答错" + exam.getNumOfWrong() +
"题," + "用时" + exam.getCostTime();
checkD.setVisible(false);
examD.setVisible(false);
file = null;
exam = null;
uploadT.setText("");
resultL.setText(result);
resultD.setVisible(true);
}

添加监听器等各种UI的实现细节不用细说,因为显而易见。

结对过程:

在项目开始时,两人先对项目进行了需求分析和初步设计,然后我们进行了分工(我负责计算模块代码,邵汝佳负责UI的代码)。我花了一天的时间初步实现Command,然后我们又线下对代码进行单元测试,(我们的单元测试比较灵活,在一个main方法里测试许多单元,我们没有进行分别保存,这是个疏漏。)同时我又单独在产生错误的地方进行回归测试,尽力保证代码的健壮性。当我们负责的模块都初步实现了,由我对各模块进行拼接(实际上我重构了UI代码T-T,因为我读partner的源码比较困难)。感觉结对项目这种方式适合基础还行的 ,感觉我们的基础还不行,效能分析只能通过分析设计来估算,而不会用专业工具(即使有教程,笨)。至于单元测试,编程的过程中是必须用的,我理解的单元测试是保证细小模块的功能运行正常,但是测试有没有疏漏就在于单元测试代码的覆盖率。然而,我编程的时候,却很少正规地进行单元测试,现在想起还是必要的。至于coding.net的源代码管理那就更不会用了,我直至现在还把它当做一个网盘。

总之,结对编程适合有一定编程经验,懂得完整开发流程的。否则,那就不是一加一大于二,而是一加一小于二或一加一小于一了。

对partner的评价:

1,认真,为了UI编写,专门去学了UI。

2,好学,遇到问题不懂就问,对于一些JVM原理比较感兴趣。

3,耐心,会耐心测试程序中出现的bug,并汇总。

4,基础知识不扎实,编写的源码不规范。

对自己的评价:

1,辛苦,每天都在设计,编程和debug;

2,认真,项目开始前为自己设计了PSP表格并如实填写,写过设计书。

3,可以,感觉我的设计还可以,继续拓展更多的东西没问题。

4,经验不足,虽然想完全按流程进行开发,但是效率不高,开发中学习耽搁的时间太多。导致这次项目的单元测试不正规,以及没有做精确的效能分析。

EGener2四则运算出题器的更多相关文章

  1. C++四则运算出题器---有答案版

    一.实验题目 四则运算扩展----能接受答案并判断对错然后给出成绩. 二.实验思路 在每次输出算式后面输入答案,然后判断对错,对则统计. 稍微优化了一下界面. 三.代码 // 12345.cpp : ...

  2. 四则运算出题器(C++)-BUG修复

    定制题目数量这个功能测试: (1)输入题目数为负数时: 可正确处理: (2)输入题目数量为0时: 可正确处理: (3)输入题目数量为小数时: 程序运行出错: 错误分析: 因为代码中题目数量的变量Que ...

  3. 四则运算出题器(c++)

    一.设计思路 这次版本加入了一下功能: 可定制题目的数量:修改循环次数: 可以定制每行打印的题目数和行间距的大小(当前题目序号可以整除定制数时输出输入的行间距个换行符): 可以定制算式的范围(修改随机 ...

  4. 小学生四则运算出题软件-基于java控制台的实现

    .题目描述: 1. 使用 -n 参数控制生成题目的个数,例如 Myapp.exe -n 10 -o Exercise.txt 将生成10个题目. 2. 使用 -r 参数控制题目中数值(自然数.真分数和 ...

  5. paperOne基于java web的简易四则运算出题网站

    项目成员:张金生     张政 需求概要 1.运算数均为正整数 2.包含的运算符有+,-,*,/ 3.除法运算结果为整除运算 4.批量生成题目并判题 核心功能分析 1.题目生成——java后端 题目生 ...

  6. 结对编程——paperOne基于java web的简易四则运算出题网站

    项目成员:张金生     张政 需求分析: 1.要进行四则运算: 2.运算题目随机: 3.进行对错判断: 4.整数运算. 程序概要: 1.用JSP实现: 2.用户可选择题目数量: 3.答题页用表格列出 ...

  7. 小学生四则运算出题程序 无操作界面java版 简单的运用java中一些基本操作

    这是本学期java课中实验大纲里的第一个实验,这里简单做了一个无用户界面版本. import java.util.Random; import java.util.Scanner; public cl ...

  8. 结对项目-四则运算出题程序(GUI版)

    目录: 一.致搭档(含项目地址) 二.PSP(planning) 三.结对编程中对接口的设计 四.计算模块接口的设计与实现过程 五.计算模块接口部分的性能改进 六.计算模块部分单元测试展示 七.计算模 ...

  9. 四则运算出题系统,java

    程序设计思想: 首先通过判断选择计算的范围,然后用随机数生成两个随机数,定义另一个数,将两个随机数计算得到的值赋给定义的数 程序代码: package Kaos1; import java.util. ...

随机推荐

  1. 定心丸!ZipperDown漏洞分析与修复建议

    本文由  网易云发布. 近日,盘古实验室对外披露了ZipperDown漏洞,该漏洞是盘古团队针对不同客户的iOS应用安全审计的过程中发现的,大约有10%的iOS应用会受到此漏洞的影响. 利用此漏洞可以 ...

  2. 大数据入门第十一天——hive详解(一)入门与安装

    一.基本概念 1.什么是hive The Apache Hive ™ data warehouse software facilitates reading, writing, and managin ...

  3. JSON解析工具——Jackson的简单使用

    什么是Jackson 可以轻松实现Java对象与JSON字符串的转换 准备工作:导包 Jackson的jar all下载地址:http://jackson.codehaus.org/1.7.6/jac ...

  4. VB6 Common Dialog

    '---------------------------- 'Class CommonDialog 'Member of MSComDlg '---------------------------- ...

  5. django学习笔记(3)

    Part 3: Views and templates ====> Write your first view$ edit polls\views.py from django.http imp ...

  6. 洛谷 P2563 [AHOI2001]质数和分解

    洛谷  P2563 [AHOI2001]质数和分解 题目描述 任何大于 1 的自然数 n 都可以写成若干个大于等于 2 且小于等于 n 的质数之和表达式(包括只有一个数构成的和表达式的情况),并且可能 ...

  7. 消息队列ZeroMQ

    消息队列概念 消息队列技术是分布式应用间交换信息的一种技术.消息队列可以驻留在内存或者磁盘上,队列存储消息直到它们被应用程序读走.通过消息队列,应用程序可以独立的执行,它们不需要知道彼此的位置,或者在 ...

  8. BZOJ 2395 [Balkan 2011]Time is money

    题面 题解 将\(\sum_i c_i\)和\(\sum_i t_i\)分别看做分别看做\(x\)和\(y\),投射到平面直角坐标系中,于是就是找\(xy\)最小的点 于是可以先找出\(x\)最小的点 ...

  9. 按键精灵手机版多点找色,图片对比 by <剑行洪荒> 忠哥

    代码: Do    Dim ret1,ret2    Delay 500    ret1 = CmpColor(76,72, "153274", 0.9)    ret2 = Cm ...

  10. linux 修改文件最大数

    ulimit -a 查看所有 open files (-n) 1024 是linux操作系统对一个进程打开的文件句柄数量的限制(也包含打开的套接字数量) ulimit -SHn 10000 ##临时修 ...