oop前三次作业总结
前言:
这是我第一次写oop的设计作业,其中不乏踩坑,乱设计,瞎设计,但三次题目都能很好的提高个人能力,这是我跨入面向对象的第一步,只有第一步走踏实了,后面的课中,才能走的更快更稳,更稳更远。
- 写前三次作业的过程中,每个题目都要求合理正确设计各种类,要求实现类的封装性,合理设计类间关系,符合类的单一职责原则,熟悉正则表达式。
第一次题目集较为简单,需要设计的类较少,即可完成题目。
第二次题目集前三题仍然比较简单,第四题在第一次题目集最后一题的基础上进行迭代,增加类的数量,题目难度较第一次加大,总体来说,不算太难。
第三次题目集共三题,前两题题目内容较少,稍花时间设计即可顺利完成,最后一题依旧在前俩次题目的基础上进行进一步迭代,难度中等。
设计与分析:
- 对于第一次作业最后一题:
点击查看代码
class Question {
private int number;
private String content;
private String standardAnswer;
public Question(int number, String content, String standardAnswer) {
this.number = number;
this.content = content;
this.standardAnswer = standardAnswer;
}
public int getNumber() {
return number;
}
public String getContent() {
return content;
}
public String getStandardAnswer() {
return standardAnswer;
}
public boolean checkAnswer(String answer) {
return answer.equals(standardAnswer);
}
}
class Paper {
private List<Question> questions = new ArrayList<>();
public void addQuestion(Question question) {
questions.add(question);
}
public Question getQuestion_Number(int number) {
for (Question question : questions) {
if (question.getNumber() == number) {
return question;
}
}
return null;
}
}
class Answer {
private Paper paper;
private ArrayList<String> answers = new ArrayList<>();
private ArrayList<Boolean> results = new ArrayList<>();
public Answer(Paper paper) {
this.paper = paper;
}
public void saveOne_Your_answer(String answer) {
answers.add(answer);
}
public void saveAnswers() {
for (int i = 0; i < answers.size(); i++) {
Question question = paper.getQuestion_Number(i + 1);
if (question != null) {
results.add(question.checkAnswer(answers.get(i)));
}
}
}
public void outputResults() {
for (int i = 0; i < answers.size(); i++) {
Question question = paper.getQuestion_Number(i + 1);
if (question != null) {
System.out.println(question.getContent() + "~" + answers.get(i));
}
}
int i=0;
for (boolean result : results) {
if(i!=0){
System.out.print(" " + result);
} else {
System.out.print(result);
}
i++;
}
}
}
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int questionNumber = sc.nextInt();
sc.nextLine();
Paper paper = new Paper();
Answer answerSheet = new Answer(paper);
for(int i=0;i<questionNumber;i++){
String line = sc.nextLine();
Matcher matcher = Pattern.compile("#N:(\\s+)?(\\S+)(\\s+)?#Q:(\\s+)?(.+)#A:(\\s+)?(.+)").matcher(line);
if (matcher.find()) {
int number = Integer.parseInt(matcher.group(2));
String content = matcher.group(5);
content=content.trim();
String standardAnswer = matcher.group(7);
paper.addQuestion(new Question(number, content, standardAnswer));
}
}
while(true){
String line = sc.nextLine();
if (line.equals("end")) {
break;
}
String regex = "#A:(\\s+)?(\\S+)";
Matcher matcher = Pattern.compile(regex).matcher(line);
int matchCount = 0;
while (matcher.find()) {
matchCount++;
String your_answer = matcher.group(2);
answerSheet.saveOne_Your_answer(your_answer);
}
}
answerSheet.saveAnswers();
answerSheet.outputResults();
}
}
- 定义了如下的几个类:
Question 类:定义了问题的编号、内容以及标准答案,并提供了检查答案的方法。
Paper 类:包含了一个问题的列表,并提供添加问题和通过编号获取问题的方法。
Answer 类:包含了一个试卷的引用,存储了用户的答案和每个答案的检查结果。 - 代码逻辑:
主类 Main 的 main 方法开始执行时,
读取问题数量,然后根据题目数量循环使用正则表达式读取每个问题的编号、内容和标准答案,并添加到试卷中。
保存答案,并检查每个答案的正确性。
第一次类图
-
代码分析:
-
输入处理:代码使用正则表达式解析输入行,这是处理此类问题的有效方法。
-
错误处理:代码中没有对于输入内容的错误处理机制。如果输入格式不正确,程序可能会崩溃。
-
代码可读性:正则表达式较为复杂,不易于理解。另外,一些变量和方法命名可以更具描述性。
-
代码效率:在 Answer 类的 saveAnswers 方法中,每次循环都调用 paper.getQuestion_Number(i + 1),这并不高效的,因为可以事先获取所有问题,再保存试卷中,可以有效提高效率
-
对于第二次作业最后一题:
第二次类图
-
分析:
-
定义了如下的类:
Question 类:定义了问题的编号、内容以及标准答案,并提供了检查答案的方法。
Paper 类:包含了一个问题的列表和每个问题的分数,提供了添加问题和通过编号获取问题的方法。
Answersheet 类:包含了一个试卷的引用和用户的答案,提供了保存答案、获取结果、输出结果等方法。 -
代码逻辑:
主类 Main 的 main 方法开始执行时,创建了一个二维数组用于存储试卷问题的编号和分数,以及一些集合用于存储试卷、答题卡和结果。
通过正则表达式解析输入行,处理题目、试卷编号、分数、用户答案等信息。
根据试卷编号和题目编号,获取用户答案并检查结果,最后输出每道题目的内容、用户答案、正确与否以及得分。 -
代码分析:
-
输入处理:代码使用多个正则表达式来解析不同格式的输入,这在处理复杂输入时是必要的。
-
数据结构:使用了合适的数据结构,如列表、哈希表等来存储题目、试卷、答题卡等信息。
-
逻辑设计:通过循环嵌套来处理多个试卷、多个题目。
-
对于第三次作业最后一题:
点击查看部分代码
class Question{
private int question_num;
private String question_content;
private String question_standardAnswer;
private boolean if_effective = true;
public Question() {
}
public Question(int question_num, String question_content, String question_standardAnswer) {
this.question_num = question_num;
this.question_content = question_content;
this.question_standardAnswer = question_standardAnswer;
}
public int getQuestion_num() {
return question_num;
}
public String getQuestion_content() {
return question_content;
}
public String getQuestion_standardAnswer() {
return question_standardAnswer;
}
public boolean isIf_effective() {
return if_effective;
}
public void setIf_effective(boolean if_effective) {
this.if_effective = if_effective;
}
public boolean judge_right_or_wrong(String answer){
return answer.equals(question_standardAnswer);
}
}
class Question_Set{
HashMap<Integer, Question> question_set = new HashMap<>();
public Question_Set() {
}
public void addQuestion_set(Integer question_num, Question question){
question_set.put(question_num,question);
}
public Question getQuestion_of_set(Integer paper_question_number){
return question_set.get(paper_question_number);
}
public boolean containsKey(int remove_number) {
return question_set.containsKey(remove_number);
}
}
class Paper{
ArrayList<Question> questions = new ArrayList<>();
HashMap<Integer,Integer> questions_score = new HashMap<>();
ArrayList<Integer> answer_order = new ArrayList<>();
Question new_question = new Question(0,"0","0");
public Paper() {
questions.add(new_question);
}
public void addQuestion(Question question){
questions.add(question);
}
public void addQuestion_score(int question_number,int score){
questions_score.put(question_number,score);
}
public void addAnswer_order(int order_num){
answer_order.add(order_num);
}//答题顺序
}
class Answersheet{
private int total_answer_number = 0;
// Answer new_answer = new Answer();
// ArrayList<Answer> answers = new ArrayList<>();
HashMap<Integer,Answer> answers = new HashMap<>();
// public Answersheet() {answers.add(new_answer);
// }
public int getTotal_answer_number() {
return total_answer_number;
}
public void add_your_answer(int order_num,Answer answer){
answers.put(order_num,answer);
this.total_answer_number++;
}
}
class Student{
private String id;
private String name;
HashMap<String,Answersheet> students_to_answersheet = new HashMap<>();//id->答卷卷子
public Student() {
}
public void setId(String id) {
this.id = id;
}
public void setName(String name) {
this.name = name;
}
public String getId() {
return id;
}
public String getName() {
return name;
}
}
class Output{
HashMap<String,Integer> id_for_answer = new HashMap<>();
ArrayList<String> student_order = new ArrayList<>();
ArrayList<Student> students = new ArrayList<>();
HashMap<Integer,Paper> papers = new HashMap<>();
Question_Set question_set = new Question_Set();
ArrayList <Integer> un_question_set = new ArrayList<>();
public Output() {
}
public void save_paper_set(Integer paper_num,Paper paper){
papers.put(paper_num,paper);
}
public void save_student_answer(String id,Integer paper_num){
id_for_answer.put(id,paper_num);
student_order.add(id);
}
public void output_question_and_result(){
for(String student : student_order){//确定答题学生
int []score = new int[105];
Arrays.fill(score, 0);
int count_answer_question = 0;
for(Student new_student : students){//寻找该学生
if(new_student.getId().equals(student)){
int answer_paper_num = id_for_answer.get(student);//寻找所答试卷编号
Paper paper = papers.get(answer_paper_num);
if(paper!=null){
for(Integer answer_num : paper.answer_order){//找所答题目 T
for(Question question : paper.questions){//2 N
if(question!=null) {
if(question.getQuestion_num()==0){
continue;
}
// System.out.println(question.getQuestion_num());
if (question.getQuestion_num() == answer_num) {
if (question.isIf_effective() && !question.getQuestion_content().equals("null_content")) {//题目有效
System.out.print(question.getQuestion_content() + "~");//输出题目内容
String your_answer = new_student.students_to_answersheet.get(student).answers.get(count_answer_question+1).getYour_answer();//你的答案
System.out.println(your_answer + "~" + question.judge_right_or_wrong(your_answer));//结果
if (question.judge_right_or_wrong(your_answer)) {//题目正确
score[count_answer_question] = paper.questions_score.get(question.getQuestion_num());
}
} else {//题目无效
if (answer_num > new_student.students_to_answersheet.get(student).getTotal_answer_number()) {
System.out.println("answer is null");
} else {
// int Num = new_student.students.get(student).answers.get(answer_num).getOrder_num();
// System.out.println(Num);
// System.out.print("*");System.out.println(answer_num);
if (question.getQuestion_content().equals("null_content")||question.getQuestion_standardAnswer().equals("null_answer")) {
System.out.println("non-existent question~0");
} else {
System.out.print("the question ");
System.out.print(question.getQuestion_num());
System.out.println(" invalid~0");
}
}
}
count_answer_question++;
break;
} else{
for(Integer a : un_question_set){
if(Objects.equals(a, answer_num)){
System.out.println("non-existent question~0");
count_answer_question++;
break;
}
}
}
}
}
}
System.out.print(new_student.getId() + " " + new_student.getName() + ":");
int sum_score = 0;
for(int i=0;i<count_answer_question;i++){
System.out.print(" ");System.out.print(score[i]);
sum_score += score[i];
}
System.out.print("~");System.out.println(sum_score);
} else {
System.out.println("The test paper number does not exist");
}
}
}
}
}
}
-
代码逻辑:
主类的Main中的main中,利用while(true)死循环循环输入各种题目,试卷,学生信息,经过正则表达式进行匹配后存入各个List对应相应的类中,然后,遍历学生列表,根据学生答题情况输出题目内容、学生答案、结果以及得分。 -
代码分析:
-
数据结构:使用了合适的数据结构来存储题目、试卷、学生答题情况等信息,HashMap、ArrayList 等。
-
逻辑设计:通过多个类的组合和方法调用,实现了题目、试卷、学生答题等功能。
采坑心得:
-
第一次作业:
1.这道题目需要正确读入输入的数据,注意错误的格式输入,例如空白字符等,要运用正则表达式进行匹配正确输入的字符
2.输入的题号可能不连续,因此直接使用数组索引可能不合适,需要逻辑映射题号到数组或List索引 -
第二次作业:
1.在使用List储存类时,容易遇到存储不当,使得类有可能会出现为null的情况
2.没有合理设计各个类的作用,使用大量方法在Main类中,代码冗杂,不易读
3.拘泥于第一题的模板和格式,没有新增类用于处理第二题新增的输入和处理,导致单独一个类中的方法很冗余,复杂,在运行第二题时,没有设计多个类的方式高效简洁和可复用性,使得下面的第三题需要重新设计类和结构。(怎么会这么愚蠢还只设计三个类TT) -
第三次作业:
1.类间关系设计的很复杂,没有完全符合类的单一职责原则,有的类中甚至只有属性和getter setter,和构造方法,没有尽到这个类中该尽的职责。
2.各个方法之间有重复代码,没有理清题目含义,出现大量无效、低效代码
3.对于输入的错误格式(如空白字符等),容易遗漏判断错误的格式情况,没有能正确处理输入,输出对应应该输出的答案。
4.对于遍历各个列表进行遍历输出数据的时候,循环过于繁杂,遇到出现null或者输入的是错误格式的代码时,只会一昧的在循环的各个地方加上if判断,没有复用性,且不易理解TT
5.对于新增的输出,学生,需要新建一个Student类,但在设计类时思路出现一点问题,Student应该在答卷类内,而我却由Student之内储存答卷,这会使得一些题目输入的无效格式难以处理,极不方便。
踩坑总结:
- 在写题时,需要先认真审题,好好厘清题目需求,不能写一步看一步,要注重整体,对类要物尽其用,充分发挥类的职责,不能把活全交给一个或几个类里面去处理,要合理利用类间关系,将输入的数据整合题目需求,高效简洁的输出,同时满足设计时应满足的几个原则(例如:里氏代换,依赖倒转,单一职责等)。(还得加油TT)
改进建议:
-
第一次作业:
可以单独设计一个类用于储存题目到试卷中,防止违反类的单一职责原则,让类的用途更清晰 -
第二次作业:
题目的需求其实用三个类有点不足,可以设计答案类和试卷题目类,答案类可以用于保存答卷的题目,试卷题目类可以应对输入中相同一道题目在不同试卷中不同分值的情况,删除一些在第一次作业中在类中编写的不必要和重复的代码,统一调用在新类的方法,可以使代码更加高效,更加简洁,增加可复用性。 -
第三次作业:
这次作业的场景需处理多张试卷,多张答卷,多个学生,新增了学生信息、删除题目信息以及多种异常输入的监测。
应该新增试卷题目类(Question_Paper):用于保存试卷中的题目信息。由于试卷中的题目序号与题目本身的题号不一致。且题目在不同试卷中的分值可能不一样,因此,设计试卷题目类转门用于处理
其次对于题目可能输入的各种错误输入,需要在各个对应的类中,专门添加一些类来处理这些信息,将其试卷或者题目或者答卷给定为无效,删除改进前在Output类中的多层嵌套循环,改为调用类的方法内的循环,将复杂循环简单化
总结
- 前三次的作业中,答题判题程序题目由浅入深,在题目中,学会了处理以下几点:
1.学会使用正则表达式处理不同格式的输入信息,包括题目信息、试卷信息、学生信息、答题信息以及删除题目信息等,对信息进行解析和分类处理。
2.需要设计合适的数据结构来存储题目信息、试卷信息、学生信息以及答题信息,以方便后续的操作和管理。
3.需要设计逻辑来判断答题的正确性、计算得分,处理删除题目信息等情况,要考虑各种可能的异常情况并给出合适的处理方式。
4.需要合理设计类间关系
5.需要考虑各种可能的异常情况,如格式错误、题目引用错误、学号引用错误等,给出相应的提示信息,保证程序的健壮性。 - 但是,我在这三次作业中,仍然有很多不足,只有第一题在规定时间内,通过了全部测试点,自己的编程,设计能力仍然还需提高,对于老师上课讲的基本的类间关系还不太熟悉,处理题目的逻辑也很乱,需要加强对题目的理解能力。
- 在这些题目中我需要加深对于需求不断的题目的处理问题能力,提高一定编程能力,加深设计能力,以处理之后难度逐渐加大,题目更加复杂的需求。
- 对于老师的授课方式,我觉得很合理,线上线下相结合,对于线下没有理解的方面,可以在线上反复观看。但是对于题目中一些难以理解的一些输入输出,可以适当添加一些样例来辅助理解题目含义,题目内最好不要出现自相矛盾的地方,比如删除了某些题目的试卷已不再是100分,却无警告信息输出,但能通过测试样例,可以适当增加测试样例更加符合现实中的对应情况
- 最后我希望后面三次作业能够弥补前面出现的不足,再接再厉,oop我来辣 ^O^/
posted on 2024-04-20 16:59 oblivioner 阅读(42) 评论(0) 编辑 收藏 举报