面向对象程序设计第三次博客作业
一、前言
此次题目集基本是围绕“课程成绩统计系统”,难度相较于点菜系统来说要容易一点,主要是类间关系更为清晰。主要涉及的知识点仍然是类间关系的设计、正则表达式的运用以及字符串的处理,其余知识点还有Map、Set、Comparable接口的运用。
二、设计与分析
(1)、课程成绩统计程序-1
某高校课程从性质上分为:必修课、选修课,从考核方式上分为:考试、考察。
考试的总成绩由平时成绩、期末成绩分别乘以权重值得出,比如平时成绩权重0.3,期末成绩权重0.7,总成绩=平时成绩*0.3+期末成绩*0.7。
考察的总成绩直接等于期末成绩
必修课的考核方式必须为考试,选修课可以选择考试、考察任一考核方式。
1、输入:
包括课程、课程成绩两类信息。
课程信息包括:课程名称、课程性质、考核方式(可选,如果性质是必修课,考核方式可以没有)三个数据项。
课程信息格式:课程名称+英文空格+课程性质+英文空格+考核方式
课程性质输入项:必修、选修
考核方式输入选项:考试、考察
课程成绩信息包括:学号、姓名、课程名称、平时成绩(可选)、期末成绩
课程信息格式:学号+英文空格+姓名+英文空格+课程名称+英文空格+平时成绩+英文空格+期末成绩
以上信息的相关约束:
1)平时成绩和期末成绩的权重默认为0.3、0.7
2)成绩是整数,不包含小数部分,成绩的取值范围是【0,100】
3)学号由8位数字组成
4)姓名不超过10个字符
5)课程名称不超过10个字符
6)不特别输入班级信息,班级号是学号的前6位。
2、输出:
输出包含三个部分,包括学生所有课程总成绩的平均分、单门课程成绩平均分、单门课程总成绩平均分、班级所有课程总成绩平均分。
为避免误差,平均分的计算方法为累加所有符合条件的单个成绩,最后除以总数。
1)学生课程总成绩平均分按学号由低到高排序输出
格式:学号+英文空格+姓名+英文空格+总成绩平均分
如果某个学生没有任何成绩信息,输出:学号+英文空格+姓名+英文空格+"did not take any exams"
2)单门课程成绩平均分分为三个分值:平时成绩平均分(可选)、期末考试平均分、总成绩平均分,按课程名称的字符顺序输出
格式:课程名称+英文空格+平时成绩平均分+英文空格+期末考试平均分+英文空格+总成绩平均分
如果某门课程没有任何成绩信息,输出:课程名称+英文空格+"has no grades yet"
3)班级所有课程总成绩平均分按班级由低到高排序输出
格式:班级号+英文空格+总成绩平均分
如果某个班级没有任何成绩信息,输出:班级名称+英文空格+ "has no grades yet"
异常情况:
1)如果解析某个成绩信息时,课程名称不在已输入的课程列表中,输出:学号+英文空格+姓名+英文空格+":"+课程名称+英文空格+"does not exist"
2)如果解析某个成绩信息时,输入的成绩数量和课程的考核方式不匹配,输出:学号+英文空格+姓名+英文空格+": access mode mismatch"
以上两种情况如果同时出现,按第一种情况输出结果。
3)如果解析某个课程信息时,输入的课程性质和课程的考核方式不匹配,输出:课程名称+" : course type & access mode mismatch"
4)格式错误以及其他信息异常如成绩超出范围等,均按格式错误处理,输出"wrong format"
5)若出现重复的课程/成绩信息,只保留第一个课程信息,忽略后面输入的。
信息约束:
1)成绩平均分只取整数部分,小数部分丢弃
此次题目我觉得思路是没什么太大问题的,但由于行数超限了,排序的方法没有加进去,将在下一道题进行分析。首先此次题目的首要是字符串中信息的提取,我先是按照信息录入的格式写了两个正则表达式分别匹配课程信息与学生信息,然后再输入信息进行匹配后以split方法将字符串内容存入数组,再通过类的有参构造方法将信息传入链表中。通过while语句不断录入信息储存数据的过程中也要进行数据的处理。这里在下一题进行分析,因为在这一题我的处理上存在问题。主要看看数据的存储。
首先是正则表达式
String str1 = "[\\u4e00-\\u9fa5\\w]{1,10} (必修|(必修 考试)|(选修 考试)|(选修 考察)|(必修 考察))"; //匹配课程信息 String str2 = "\\d{8} [\\u4e00-\\u9fa5\\w]{1,10} [\\u4e00-\\u9fa5\\w]{1,10}( )?(100|0|[1-9]([0-9])?)? (100|0|[1-9]([0-9])?)"; //匹配学生信息
然后是判断是否继续对传入字符串进行处理
while(!str.equals("end")){ /* 略 */ str = input.nextLine(); }
接下来是字符串的匹配
if(str.matches(str1)){ }else if(str.matches(str2)) { }else{ System.out.println("wrong format"); }
然后是数据的初步处理
String[] info = str.split(" ");
最后是通过一系列if语句判断后,将数据通过类的有参构造方法进行传输与储存,如:
if (isInClass) { classes.get(i).findStudent(info[0]).courses.add(new Course(info[2], Integer.parseInt(info[3]), Integer.parseInt(info[4]))); }
class Course { private String name; private String type; private String testWay; // Scores scores; private boolean isTest = false; private int generalScore; private int examineScore; public Course(String name, String type, String testWay) { this.name = name; this.type = type; this.testWay = testWay; } public Course(String name, String type) { this.name = name; this.type = type; } public Course(String name,int generalScore,int examineScore){ this.name = name; this.generalScore = generalScore; this.examineScore = examineScore; } public Course(String name,int examineScore){ this.name = name; this.examineScore = examineScore; } }
数据的储存就是这样,本题就分析到这。
(2)、课程成绩统计程序-2
本次题目添加了实验这一课程性质以及考核方式,写法与上一题基本一样。下面是其不同的地方。String str4 = "[\\u4e00-\\u9fa5\\w]{1,10} ((必修 考察)|(必修 实验)|(选修 实验)|(实验 考试)|(实验 考察))";//匹配看课程性质与考核方式是否相符 String str1 = "[\\u4e00-\\u9fa5\\w]{1,10} (必修|(必修 考试)|(选修 考试)|(选修 考察)|(实验 实验)|(必修 考察)|)"; //匹配课程信息 String str2 = "\\d{8} [\\u4e00-\\u9fa5\\w]{1,10} [\\u4e00-\\u9fa5\\w]{1,10}( )?(100|0|[1-9]([0-9])?)? (100|0|[1-9]([0-9])?)"; //匹配学生信息(无实验课) String str3 = "\\d{8} [\\u4e00-\\u9fa5\\w]{1,10} [\\u4e00-\\u9fa5\\w]{1,10} [4-9]( \\b(0|[1-9]\\d?|100)\\s*(\\b(0|[1-9]\\d?|100)\\s*)*\\b)?";//匹配学生信息(有实验课)
然后就是这次程序我写好了比较排序方法,在几个类中实现Comparable接口,在主函数中进行比较
class Class implements Comparable { @Override public int compareTo(Object o) {//进行班级大小的比较 Class cl = (Class)o; if(Integer.parseInt(this.num) < Integer.parseInt(cl.num)){ return -1; }else if(Integer.parseInt(this.num) > Integer.parseInt(cl.num)){ return 1; } return 0; } }
Collections.sort(classes);//班级排序 for(Class x : classes){ Collections.sort(x.list1);//各班学生按学号排序 } Collections.sort(courseSelection.courses);/按课程名称进行排序
接下来分析输出的处理
先进行异常处理,其中第一步是看课程性质与考核方式是否匹配
if(str.matches(str4)){ System.out.println(info[0]+" : course type & access mode mismatch"); }
当输入字符串匹配的是课程信息时无异常处理进行数据的存储
else if(str.matches(str1)){//(无实验) boolean flag = true;//分别课程是否已存在 for(Course course : courseSelection.courses){ if(info[0].equals(course.getNmae())){ flag = false; break; } } if(flag){//课程不存在则加入 if(info.length == 2){//必修 courseSelection.addCourse(info[0],info[1]); }else if(info.length == 3){//必修或选修 courseSelection.addCourse(info[0],info[1],info[2]); } } }
匹配带实验课的课程信息
else if(str.matches(str2)) { boolean flag2 = true;//看课程是否已存在 boolean isInClass = false;//看学生在班级内是否已存在 for (Class class2 : classes) { for (Student student1 : class2.list1) { if (student1.getNumber().equals(info[0]) && student1.getName().equals(info[1])) { isInClass = true; for (Course course : student1.courses) { if (course.getNmae().equals(info[2])) { flag2 = false; break; } } if (!flag2) { break; } } if (!flag2) { break; } } } if (flag2) {//若课程不存在 boolean flag1 = false;//看班级是否存在 int i; for (i = 0; i < classes.size(); i++) { if (classes.get(i).getNum().equals(info[0].substring(0, 6))) { flag1 = true; break; } } if (courseSelection.findCourse(info[2]) == null) {//学生所考的课程在课程信息中不存在 System.out.println(info[2] + " " + "does not exist"); if(flag1){//班级存在则直接加入学生 classes.get(i).addStudent(info[0],info[1]); }else{//班级不存在则先创建班级再加入学生 classes.add(new Class(info[0])); classes.get(classes.size()-1).addStudent(info[0],info[1]); } }
else if ((courseSelection.findCourse(info[2]).getTestWay().equals("考试") && info.length == 4) || (courseSelection.findCourse(info[2]).getTestWay().equals("考察") && info.length == 5)) {//成绩数量和课程的考核方式不匹配
System.out.println(info[0] + " " + info[1] + " : access mode mismatch");
if (flag1) {//班级存在则直接加入学生
classes.get(i).addStudent(info[0], info[1]);
} else {//不存在则先创建班级
classes.add(new Class(info[0]));
classes.get(classes.size() - 1).addStudent(info[0], info[1]);
}
} else {//没有异常的情况
if (info.length == 5) {//通过长的判断是那种课程性质
if (flag1) {//班级存在
if (isInClass) {//学生存在
classes.get(i).findStudent(info[0]).courses.add(new Course(info[2], Integer.parseInt(info[3]), Integer.parseInt(info[4])));//找到学生,存入数据
} else {//学生不存在
classes.get(i).addStudent(info[0], info[1], info[2], Integer.parseInt(info[3]), Integer.parseInt(info[4]));//找到班级添加学生及数据
}
} else {//班级不存在则创建班级后添加学生信息
classes.add(new Class(info[0]));
classes.get(classes.size() - 1).addStudent(info[0], info[1], info[2], Integer.parseInt(info[3]), Integer.parseInt(info[4]));
}
} else if (info.length == 4) {//和上一段一样的逻辑
if (flag1) {
if (isInClass) {
classes.get(i).findStudent(info[0]).courses.add(new Course(info[2], Integer.parseInt(info[3])));
} else {
classes.get(i).addStudent(info[0], info[1], info[2], Integer.parseInt(info[3]));
}
} else {
classes.add(new Class(info[0]));
classes.get(classes.size() - 1).addStudent(info[0], info[1], info[2], Integer.parseInt(info[3]));
}
}
}
}
}
再然后匹配含实验课的信息时写法与上面是一致的,就不进行分析了,直接分析最后的正确输出
//在上面已经进行好了排序
//输出学生成绩 for(Class c : classes){ for(Student student : c.list1){ if(student.courses.size() == 0){ System.out.println(student.getNumber() + " " + student.getName() + " did not take any exams"); }else{ c.setHaveScore(true); System.out.println(student.getNumber() + " " + student.getName() + " "+student.getScore(courseSelection)); } } } //输出科目成绩,先将每一一个学生成绩加起来,最后在取平均值 for(Course course : courseSelection.courses){ if(course.getIsTest()){ double examineScore = 0; double testScore = 0; double experimentScore = 0; int count = 0; int count1 = 0; int sum = 0; for(Class class3 : classes){ for(Student student3 : class3.list1){ if(student3.findCourse(course.getNmae()) != null){ if(course.getTestWay().equals("考试")){ examineScore += student3.findCourse(course.getNmae()).getGeneralScore(); testScore += student3.findCourse(course.getNmae()).getExamineScore(); sum += (int)(0.3*student3.findCourse(course.getNmae()).getGeneralScore() + 0.7*student3.findCourse(course.getNmae()).getExamineScore()); }else if(course.getTestWay().equals("考察")){ testScore += student3.findCourse(course.getNmae()).getExamineScore(); }else if(course.getTestWay().equals("实验")){ for(int i = 0; i<student3.findCourse(course.getNmae()).getExperimentTimes();i++){ count1++; experimentScore += student3.findCourse(course.getNmae()).getExperiment()[i]; } } count++; } } } if(course.getTestWay().equals("考试")){ System.out.println(course.getNmae() + " " + (int)(examineScore/count) + " " + (int)(testScore/count) + " " + sum/count); }else if(course.getTestWay().equals("考察")){ System.out.println(course.getNmae() + " " + (int)(testScore/count) + " " + (int)(testScore/count)); }else if(course.getTestWay().equals("实验")){ System.out.println(course.getNmae() + " " + (int)(experimentScore/count1)); } }else{ System.out.println(course.getNmae()+" "+"has no grades yet"); } } //输出班级成绩 for(Class class4 : classes){ if(class4.isHaveScore()){ System.out.println(class4.getNum() + " " + class4.getScore(courseSelection)); }else{ System.out.println(class4.getNum() + " " + "has no grades yet"); } }
代码分析就到这了,接下来是这一程序的类图,边上两个图是不小心复制出来的
(3)总结
1、基础知识不扎实,像正则表达式部分
2、逻辑思维能力还未锻炼到位
3、类间关系的设计还需进一步学习
4、对于该课程,我觉得还可以,在课堂上会将重点需要学习的知识,便于课后学习
5、建议可以在每一次题目集完成后,可以给出正确源码进行分析
6、希望可以加上一些小组作业