项目需求
小学、初中和高中数学老师用户自动生成试卷
要完成的功能有:
- 命令行输入用户名和密码进行登录
- 登录成功显示用户可生成的题目类型,可以输入所需的题目数量(要求数量在10-30之间)
- 生成的题目保存到目标用户名文件中并以"年-月-日-时-分-秒.txt"的形式保存,每个用户名一个文件夹,题目开头有序号并且每题之间要空一行,同一账号生成的题目不允许和已生成的题目重复。
- 登录状态下,可切换老师类型
- 输入-1,可退出登录

代码分析
结构简单明了,仅使用三个类,命名符合规范,让人很容易就能知道每个类的作用。

User.java 用于存储用户数据结构,私有成员,安全性不错。

GeneratePaper.java
使用相对路径读取,生成题目,迁移方便。
三个成员函数,setProblem生成单道题,pastProblem遍历历史题目存在哈希表里。makepaper调用前面两个函数生成试卷。

Ui.java
用于用户交互,主函数调用其他类完成程序需求。
在迭代时可以用于修改,实现后端接口,拓展性好。

代码优缺点具体分析
优点
1. 检查题目是否重复使用哈希表,保证了程序性能
对于海量数据中的精确查找有非常惊人的速度提升,理论上即使有无限的数据量,一个实现良好的哈希表依旧可以保持O(1)的查找速度,而O(n)的普通列表此时已经无法正常执行查找操作(实际上不可能,受到JVM可用内存限制,机器内存限制等)。
具体代码如下:
public HashSet<String> pastProblem(File file){
HashSet<String> pastProblem= new HashSet<String>();
File[] all = file.listFiles();//all文件数组,读取用户夹
for (File file1:all){
if (!file1.isDirectory()){//非目录则读取
try {
BufferedReader reader = new BufferedReader(new FileReader(file1));
String temp = reader.readLine();
while(temp !=null){//读取到的题目存于哈希表
String[] cur=null;
if (temp.length()>2) {//将题目去题号
cur = temp.split("\\.");
pastProblem.add(cur[1]);
}
temp = reader.readLine();
}
reader.close();
}catch (Exception e){
e.printStackTrace();
}
}
}
return pastProblem;
}
2. 题目生成思路非常好,代码复用性高
先上代码,再来解说
//生成单个题目
public String setProblem(String type){
Random rand = new Random();//随机
String[] symbol = {"+", "-", "*", "/"};//共用普通字符表
int size = 0;//题目的操作数
String[] data = null;//题目中的数字
if (type.equals("小学")){
size = rand.nextInt(4)+2;//生成2-5个操作数
data = new String[size];
for (int i = 0; i<size; i++){
data[i]=String.valueOf(rand.nextInt(100)+1);
}
}
else if (type.equals("初中")) {
size = rand.nextInt(5) + 1;//生成1-5个操作数
data = new String[size];
boolean[] flag = new boolean[size];
int specialSymbol = rand.nextInt(size) + 1;//至少1个平方运算
for (int i = 0; i < size; i++) {
data[i] = String.valueOf(rand.nextInt(100) + 1);
}
for (int i = 0; i < specialSymbol; i++) {//添加初中特有字符
int index = rand.nextInt(size);
if (!flag[index]) {
if (rand.nextInt(2) == 0 ) {
data[index] = "√" + data[index];
} else {
data[index] = data[index] + "²";
}
flag[index] = true;
}
}
}
else if (type.equals("高中")) {
size = rand.nextInt(5) + 1;
data = new String[size];
boolean[] flag = new boolean[size];
int specialSymbol1 = rand.nextInt(size) + 1;//至少1个角运算
int specialSymbol2 = rand.nextInt(size) + 1;//至少1个角运算
for (int i = 0; i < size; i++) {
data[i] = String.valueOf(rand.nextInt(100) + 1);
}
for (int i = 0; i < specialSymbol1; i++) {//添加角运算
int index = rand.nextInt(size);
if (!flag[index]) {
switch (rand.nextInt(3)){
case 0:
data[index] = "sin" + data[index];
break;
case 1:
data[index] = "cos" + data[index];
break;
case 2:
data[index] = "tan" + data[index];
break;
}
flag[index] = true;
}
}
for (int i = 0; i < specialSymbol2; i++) {//添加初中已学的运算
int index = rand.nextInt(size);
if (!flag[index]) {
if (rand.nextInt(2) == 0 ) {
data[index] = "√" + data[index];
} else {
data[index] = data[index] + "²";
}
flag[index] = true;
}
}
}
else {
System.out.println("非标准输入,创建有误");
}
//随机加上括号
if (size >= 3 && rand.nextInt(2) == 0) {
int gap = rand.nextInt(size - 2) + 1;
int left = rand.nextInt(size - gap);
int right = left + gap;
data[left] = "(" + data[left];
data[right] = data[right] + ")";
}
//将数字以符号连接生成题目
String problem = " ";
if (data!=null) {
problem = data[0];
for (int i = 0; i < size - 1; i++) {
problem += symbol[rand.nextInt(4)];//随机添加基础字符
problem += data[i + 1];
}
problem += "=";
}
return problem;
}
三种试卷类型公用的符号放于通用字符数组。采用数值与符号分离的方法来生成题目。三个类型都是先生成随机的操作数和具体数值,然后在数值之间以随机的通用符号连接。对于初高中的特有字符,对方没有采用与普通字符一样的处理手段,而是选择与数值绑定,存于数值所在的string数组中。另外在最后,加上括号。代码简单,逻辑清晰,实为上佳之作。
缺点
1. 导入文件不符合规范,出现通配符*

2. 一次输出信息较多,但没有对文字内容进行如加边框或居中等美化处理

3. 账号采用文本文件存储,未使用数据库,该方面可做拓展提升
总结
队友代码可读性和可维护性还是不错的,也有使用静态方法,可以直接被主函数调用,节省空间提高了效率。小问题也是有的,希望能就代码规范进行再次学习。本次我们两人选择的代码语言并不一样,在互相看代码的过程中,触发了新的思路,新的想法,同时也收获很多,期待结对项目的合作。
浙公网安备 33010602011771号