第二次java大作业
(菜鸡版)基于有状态的课堂点名系统
1. 题目与现有缺陷
- 题目:基于有状态的课堂点名系统(1人) 等级:A
现在课堂教师点名回答问题,往往是随机点名。由于教师习惯等因素往往造成有的同学被点名次数多,有的同学被点名次数少。希望设计一个点名系统使得学生在一个学期的上课过程中可以获得相同的点名机会。
导入学生功能:可从Excel或文本文件中导入学生信息,或者可以批量新建学生亦可。(自我理解:导入的是新的学生信息)
状态存储功能:该系统需记录每个学生的被点名次数,回答出问题的次数。
点名功能:每次点名选择同学时需要基于该同学已经被点名的次数(自我理解:优先级随机数/指定范围对排序后的序列随机数抽取),如果点名超过n个同学还未回答出该问题则从已有的回答出来次数较多(自我理解:可自定义n的大小)的同学中随机抽取。
统计功能:可将每个学生的被点名次数、回答出问题的次数、比率统计出来。
要求:界面Web,后台存储数据库或者文件。
进阶:基于手机app - 现有缺陷:
- 还未实现web页面
- 目前的底层存储结构不适于大量学生
- 点名功能还待完善,不知道是否正确理解了题目意思
- 目前功能只适用于某一堂课,还未实现不同课堂的点名和数据的交互
2. 功能调查与系统功能框架图
-
面向对象:老师
-
系统功能框架图:
3. UML类图
4. 类说明
-
重要的类:实现SystemDao接口的SystemDaoIml类
-
属性为private List
studentList,使用List的原因是,为方便之后进行随机点名,同时按照列表顺序将学生信息导入Excel文件中 -
主要方法:
-
public boolean importInitiallyExcel(String pathName);功能说明:将不含答题信息的学生信息Excel进行导入
-
public boolean storeStudentRollCallSystemInformation(StudentData studentData, String pathName) ;功能说明:将答题信息同步修改到指定Excel中的指定位置
-
private StudentData rollCall(List
list,HashSet hashSet);功能说明:基于某学生的点名状况进行点名,里面使用了HashSet是为了在同一道题点名时不重复点名 -
private StudentData randomRollCall(List
list,HashSet hashSet,int n);功能说明:从答题正确率高的学生中进行随机点名,里面使用了HashSet是为了在同一道题点名时不重复点名 -
public boolean oneQuestion(int n, List
list,String pathName);功能:进行一次课堂点名提问 -
public void statics() throws IOException ;功能说明:统计和显示所有同学的答题情况和个人信息
-
5. 系统的包(package)的规划设计
- dao包:
- SystemDao接口:包含课堂点名系统中对数据进行操作的方法的接口
- iml包:包含SystemDao接口的实现类SystemDaoIml,目前主要用来完成系统的各种功能
- model包:包含Student类和StudentData类,Student类为学生类,StudentData类为学生信息类
- ui包:由于题目中要求用web做页面,目前还未包含类
- util包:包含ExcelUtil类,为用POI操作Excel中的.xlsx的工具类
- service包:由于能力问题,目前还未包含类
- test包:包含Test类,目前用来初步测试现有功能
6. 特色
-
使用了POI对Excel进行导入、导出和修改操作,详看类ExcelUtil
-
使用了DAO模式,好处:可以方便修改数据的底层存储结构
-
还未使用MVC模式,web界面目前还未学习
-
进行了数据持久化,当前方案是存储在Excel中,打算之后如果有能力存储到数据库中
-
目前未使用JUnit编写测试用例
-
已经完成系统的初步原型
6. 关键代码
-
SystemDaoIml的代码
package dao.iml; import dao.SystemDao; import model.Student; import model.StudentData; import util.ExcelUtil; import java.io.IOException; import java.util.*; /** * @author 林洁颖 */ /** * 从被点名次数逆序排序的排序方法 */ class ReverseOrdermMethodOfAnswerTimes implements Comparator<StudentData> { @Override public int compare(StudentData o1, StudentData o2) { return o1.getNumberOfRollovers() - o2.getNumberOfRollovers(); } } class SortMethodOfCorrectRate implements Comparator<StudentData> { @Override public int compare(StudentData o1, StudentData o2) { if (o2.getCorrectAnswerRate() - o1.getCorrectAnswerRate() == 0) { return 0; } if (o2.getCorrectAnswerRate() > o1.getCorrectAnswerRate()) { return 1; } return -1; } } public class SystemDaoIml implements SystemDao { /** * 可用来暂时存储点名系统后台信息,由于之后要用于随机数点名使用list较为方便 */ private List<StudentData> studentList; public List<StudentData> getList() { return studentList; } public void setList(List<StudentData> list) { this.studentList = list; } public SystemDaoIml(List<StudentData> list) { this.studentList = list; } public SystemDaoIml(){} /** * 初始导入学生信息 * @param pathName * @return * @throws IOException */ @Override public boolean importInitiallyExcel(String pathName) throws IOException { List<StudentData>studentDataList = null; try { studentDataList=new ArrayList(ExcelUtil.importStudentExcel(pathName)); this.setList(studentDataList); return true; } catch (IOException e) { e.printStackTrace(); } return false; } /** * 看是否需要导入的学生信息中是否有学生已经存在后台信息 * @param studentList * @param studentDataList * @return */ private boolean findStudentData(List<Student> studentList,List<StudentData>studentDataList){ for(int i=0;i<studentDataList.size();i++){ for(int j=0;j<studentList.size();j++){ if(studentDataList.get(i).getStudent().equals(studentList.get(j))){ return true; } } } return false; } @Override public boolean storeStudentRollCallSystemInformation(StudentData studentData, String pathName) { if(studentData==null){ return false; } ExcelUtil.changeExcel(pathName, studentData); return true; } /** * 从被点名次数较少的人中抽一个学生,而且利用Set来避免重复点名 * @param list * @return */ private StudentData rollCall(List<StudentData> list,HashSet<StudentData>hashSet) { List<StudentData> rollCallList = new ArrayList<>(); rollCallList.addAll(list); Collections.sort(rollCallList, new ReverseOrdermMethodOfAnswerTimes()); if (hashSet.isEmpty()) { return rollCallList.get(0); } else { for (int i = 0; i < list.size(); i++ ) { if (!hashSet.contains(rollCallList.get(i))) { return rollCallList.get(i); } } } return null; } /** * 如果点名超过n个同学还未回答出该问题则从已有的回答出来次数较多的同学中随机抽取 * @param list * @return */ private StudentData randomRollCall(List<StudentData> list,HashSet<StudentData>hashSet,int n){ List<StudentData> rollCallList = new ArrayList<>(); rollCallList.addAll(list); Collections.sort(rollCallList, new SortMethodOfCorrectRate()); Random random=new Random(); int studentIndex=random.nextInt(list.size()-n+1); StudentData studentData=rollCallList.get(studentIndex); while(!hashSet.contains(studentData)){ studentIndex=random.nextInt(list.size()-n+1); return studentData; } return null; } /** * 一次点名提问 */ public boolean oneQuestion(int n, List<StudentData> list,String pathName) { if(n> list.size()){ System.out.println("n比学生人数要多,请重新设置"); return false; } HashSet<StudentData> rollCalSet=new HashSet<>(); boolean flag = false; for (int i = 0; i < n; i++) { StudentData oneStudent = rollCall(list,rollCalSet); if(oneStudent==null){ System.out.println("只能通过老师来回答这个问题了,学生回答不上来"); return false; } System.out.println(oneStudent); System.out.println("输入他答题的正确与否,true or false"); rollCalSet.add(oneStudent); Scanner scanner = new Scanner(System.in); flag = Boolean.parseBoolean(scanner.next()); for (StudentData studentData : list) { if (studentData.equals(oneStudent)) { if (flag) { studentData.setNumberOfCorrectAnswers(studentData.getNumberOfCorrectAnswers() + 1); studentData.setNumberOfRollovers(studentData.getNumberOfRollovers() + 1); studentData.setCorrectAnswerRate(studentData.getNumberOfCorrectAnswers() * 1.00 / studentData.getNumberOfRollovers()); storeStudentRollCallSystemInformation(studentData,pathName); return true; } else { studentData.setNumberOfRollovers(list.get(i).getNumberOfRollovers() + 1); studentData.setCorrectAnswerRate(list.get(i).getNumberOfCorrectAnswers() * 1.00 / list.get(i).getNumberOfRollovers()); storeStudentRollCallSystemInformation(studentData,pathName); } } } } while (!flag) { StudentData oneStudent = randomRollCall(list,rollCalSet,n); if(oneStudent==null){ System.out.println("只能通过老师来回答这个问题了,学生回答不上来"); return false; } rollCalSet.add(oneStudent); Scanner scanner = new Scanner(System.in); flag = Boolean.parseBoolean(scanner.next()); for (StudentData studentData : list) { if (studentData.equals(oneStudent)) { studentData.setNumberOfCorrectAnswers(studentData.getNumberOfCorrectAnswers() + 1); if (flag) { studentData.setNumberOfRollovers(studentData.getNumberOfRollovers() + 1); studentData.setCorrectAnswerRate(studentData.getNumberOfCorrectAnswers() * 1.00 / studentData.getNumberOfRollovers()); storeStudentRollCallSystemInformation(studentData,pathName); } else { studentData.setCorrectAnswerRate(studentData.getNumberOfCorrectAnswers() * 1.00 / studentData.getNumberOfRollovers()); storeStudentRollCallSystemInformation(studentData,pathName); } } } } return flag; } public void statics() throws IOException { for (StudentData studentData : studentList) { System.out.println(studentData); } } }