前言
截至目前,面向对象程序设计已经进行了三次PTA训练。题目是基于试卷的判分系统的程序设计,在三次训练中难度逐渐增加,同时这个题目还要伴随整个面向对象程序设计的学习,逐步迭代。完成这部分作业确实花费了我大部分时间,虽然最后的代码都可以完成所有的测试样例,但是无法通过所有的测试点,说明我的设计、语法和算法都或多或少存在问题,所以总结就是有必要的。
知识点
题量
三次PTA作业,最后一题代码量和难度逐渐增大,但是前面的小题得分少的题目逐渐减少,在一定程度上达到一个相对稳定的增加趋势。最后一题确实需要大量的时间投入才能完成。但是如果愿意投入足量的时间,还是可以完成的。
难度
现在越来越感觉到的一个问题是一个逐步迭代的题目的难与不难其实是取决于你最初的设计。如果设计良好,每一次迭代都只需要加代码(虽然对于我们这些初学者确实是有难度的),在实现功能的时候也更加简便;设计不好,可能每次迭代都要重构,在实现功能的时候也会遇到一系列问题。所以,最大的难度存在于设计。
设计与分析(第一次)
源码
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scan scan = new Scan();
scan.scanAll();
scan.cut();
scan.finalData();
TestAndAnswer[] testAndAnswer = new TestAndAnswer[scan.getN()];
for (int i = 0; i < scan.getN(); i++) {
TestAndAnswer testAndAnswer1 = new TestAndAnswer(scan.getNumber()[i],scan.getText()[i],scan.getStandardAnswer()[i],scan.getAnswer()[i+1]);
testAndAnswer[i] = testAndAnswer1;
}
Paper paper = new Paper(testAndAnswer, scan.getN());
paper.sout();
paper.judge();
paper.print();
}
}
class Paper{
private int n;
private boolean[] consequence = new boolean[2000];
TestAndAnswer[] testAndAnswer = new TestAndAnswer[2000];
Paper(){}
Paper(TestAndAnswer[] testAndAnswer,int n){
this.testAndAnswer = testAndAnswer;
this.n = n;
}
void judge(){
for (int i = 0; i < n; i++) {
if(testAndAnswer[i].getAnswer().equals(testAndAnswer[i].getStandardAnswer())){
consequence[i] = true;
}else{
consequence[i] = false;
}
}
}
void sout(){
for (int i = 0; i < n; i++) {
for (int j = 0; j < n-i-1; j++) {
if(testAndAnswer[j].getNum()>testAndAnswer[j+1].getNum()){
TestAndAnswer testAndAnswer1 =new TestAndAnswer();
testAndAnswer1 = testAndAnswer[j];
testAndAnswer[j] = testAndAnswer[j+1];
testAndAnswer[j+1] = testAndAnswer1;
}
}
}
}
void print(){
for (int i = 0; i < n; i++) {
System.out.println(testAndAnswer[i].getText() + "~" + testAndAnswer[i].getAnswer());
}
for (int i = 0; i < n; i++) {
if(i != n-1){
System.out.printf("%s ",consequence[i]);
}
else{
System.out.printf("%s",consequence[i]);
}
}
}
}
class TestAndAnswer{
private int num;
private String text;
private String standardAnswer;
private String answer;
private boolean judge;
Scan scan = new Scan();
TestAndAnswer(){}
TestAndAnswer(int num, String text, String standardAnswer, String answer){
this.num = num;
this.text = text;
this.standardAnswer = standardAnswer;
this.answer = answer;
}
public boolean isJudge() {
return judge;
}
public void setJudge(boolean judge) {
this.judge = judge;
}
public String getAnswer() {
return answer;
}
public void setAnswer(String answer) {
this.answer = answer;
}
public int getNum() {
return num;
}
public void setNum(int num) {
this.num = num;
}
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
public String getStandardAnswer() {
return standardAnswer;
}
public void setStandardAnswer(String standardAnswer) {
this.standardAnswer = standardAnswer;
}
}
class Scan{//输入并处理;
Scan(){}
public String[] getAnswer() {
return answer;
}
public void setAnswer(String[] answer) {
this.answer = answer;
}
public String[][] getAfterJudge() {
return afterJudge;
}
public void setAfterJudge(String[][] afterJudge) {
this.afterJudge = afterJudge;
}
private int n = 2000;//输入题目个数
private String end;
private String[] str1 = new String[n];
private String fin;
private String[] answer;
private String[][] afterJudge = new String[n][4];
private int[] number = new int[n];
private String[] text = new String[n];
private String[] standardAnswer = new String[n];
Scanner sc = new Scanner(System.in);
void scanAll(){//输入
n = Integer.parseInt(sc.nextLine());
for (int i = 0; i < n; i++) {
str1[i] = sc.nextLine();
}
fin = sc.nextLine();
end = sc.nextLine();
}
void cut(){//将题目剥离出来
for (int i = 0; i < n; i++) {
afterJudge[i] = str1[i].split("#N:|#Q:|#A:+|\\s+$");
}
for (int i = 0; i < n; i++) {
afterJudge[i][1] = afterJudge[i][1].replaceAll(" ","");
afterJudge[i][2] = afterJudge[i][2].replaceAll("^\\s*|\\s+$","");
}
answer = fin.split("#A:");
for (int i = 0; i < n; i++) {
answer[i] = answer[i].replaceAll("^\\s*|\\s+$","");
}
}
void finalData(){
for (int i = 0; i < n; i++) {
int num = Integer.parseInt(afterJudge[i][1]);
number[num - 1] = num;
text[num - 1] = afterJudge[i][2];
standardAnswer[num - 1] = afterJudge[i][3];
}
}
public int getN() {
return n;
}
public void setN(int n) {
this.n = n;
}
public int[] getNumber() {
return number;
}
public void setNumber(int[] number) {
this.number = number;
}
public String[] getText() {
return text;
}
public void setText(String[] text) {
this.text = text;
}
public String[] getStandardAnswer() {
return standardAnswer;
}
public void setStandardAnswer(String[] standardAnswer) {
this.standardAnswer = standardAnswer;
}
}
类图:
设计
本次设计三个类:
Scan:用于数据的输入和处理
TestAndAnswer:用于接收存储Scan的数据
Paper:对TestAndPaper中的数据进行存储并进行排序和判断
类的设计看似合理,其实出现了很大的问题:
-
SRP原则出现了很大的问题
- Scan类中将输入和多种信息处理放在同一个类中,会导致Scan类特别复杂和冗长;如果用现在的视角进行设计,可能应该将输入和处理分成两个类进行处理
-
Paper中没有采用更加合理的存储方式,导致需要完成一个复杂的循环才完成了匹配
SourceMonitor测试
从测试结果,存在以下的问题:
- Papar 的judge和print代码复杂度(Complexiety)达到最高,这明显不满足单一职责原则。既然是print,那就应该只负责输出,但在代码中出现了大量的判断,甚至是处理,这是不合理的。考虑整体架构,其实是设计出的问题
- PesentLinesWithComments注释字句的平均值只有3.3,代码的可读性太低,如果需要修改就会非常麻烦,为后期埋下了大量隐患。
设计与分析(第二次)
源码
import java.util.ArrayList;
import java.util.Scanner;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
String[] messages = new String[100];
//定义题目的对象(由于题目比较多,并且不知道数量,采用ArrayList进行存储)
ArrayList<QuestionsMessage>questionsMessages = new ArrayList<QuestionsMessage>();
//定义试卷信息对象
ArrayList<TestPaper>testPapers = new ArrayList<TestPaper>();
//定义答卷对象
ArrayList<AnswerPaper> answerPapers = new ArrayList<AnswerPaper>();
//首先,输入行数未知,输入结束的标志是“end”
int i = 0;
messages[i] = sc.nextLine();
while(!messages[i].equals("end")){
if(messages[i].startsWith("#N:")){
//第一步:筛选题目编号
String regex ="#N:(.*?)\\s#Q:";
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(messages[i]);//定义查找的相关类
int number = 0;
if(matcher.find()){
number = Integer.parseInt(matcher.group(1));
}
//第二步,筛选题目类容;
regex = "#Q:(.*?)\\s#A:";
pattern = Pattern.compile(regex);
matcher = pattern.matcher(messages[i]);
String text = "";
if(matcher.find()){
text = matcher.group(1);
}
//第三步,筛选标准答案;
regex = "#A:(.*?)(\\s|$)";//这个正则表达式需要二次检查;
pattern = Pattern.compile(regex);
matcher = pattern.matcher(messages[i]);
String answer = "";
if(matcher.find()){
answer = matcher.group(1);
}
//把捕获信息传入对象ArrayList
QuestionsMessage questionsMessage = new QuestionsMessage(number,text,answer);
questionsMessages.add(questionsMessage);
} else if (messages[i].startsWith("#T:")) {
//第一步:储存试卷号
String regex = "#T:(.*?)\\s\\d";
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(messages[i]);//定义查找的相关类
int paperNumber = 0;
if(matcher.find()){
paperNumber = Integer.parseInt(matcher.group(1));
}
//第二步:将题目和分数以字符串的形式存储;(同时注意:编号0是不需要处理的)
String[] NOAndScores = messages[i].split(" ");
//定义NumberAndScores ArrayList进行存储;
ArrayList<NumberAndScores>numberAndScores = new ArrayList<NumberAndScores>();
for (int j = 1; j < NOAndScores.length; j++) {
String[] NoScores = NOAndScores[j].split("-");
int No = Integer.parseInt(NoScores[0]);
int score = Integer.parseInt(NoScores[1]);
NumberAndScores numberAndScores1 = new NumberAndScores(No,score);
numberAndScores.add(numberAndScores1);
}
TestPaper testPaper = new TestPaper(paperNumber,numberAndScores);
testPapers.add(testPaper);
} else if (messages[i].startsWith("#S:")) {
String regex = "#S:(.*?)\\s#A:";
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(messages[i]);//定义查找的相关类
int number = 0;
if(matcher.find()){
number = Integer.parseInt(matcher.group(1));
}
//定义answer的ArrayList,并将目标信息存进answers
ArrayList<String> answers= new ArrayList<>();
regex = "#A:(.*?)(\\s|$)";
pattern = Pattern.compile(regex);
matcher = pattern.matcher(messages[i]);//定义查找的相关类
String answer = "";
while(matcher.find()){
answer = matcher.group(1);
answers.add(answer);
}
AnswerPaper answerPaper = new AnswerPaper(number,answers);
answerPapers.add(answerPaper);
// for (int j = 0; j < answerPapers.size(); j++) {
// System.out.println(number + " ");
// for (int k = 0; k < answerPapers.get(j).getAnswers().size(); k++) {
// System.out.println(answerPapers.get(j).getAnswers().get(k));
// }
// }
} //else{}
i++;
messages[i] = sc.nextLine();
}
//完成对题目信息进行排序
for (int j = 0; j < questionsMessages.size(); j++) {
for (int k = 0; k < questionsMessages.size() - j -1; k++) {
if(questionsMessages.get(k).getNo() > questionsMessages.get(k+1).getNo()){
QuestionsMessage questionsMessage = new QuestionsMessage();
questionsMessage = questionsMessages.get(k);
questionsMessages.set(k,questionsMessages.get(k+1));
questionsMessages.set(k+1,questionsMessage);
}
}
}//测试正确;
//完成对试卷(分数)信息的排序;(需要再考虑)
for (int j = 0; j < testPapers.size(); j++) {
for (int k = 0; k < testPapers.size() - j - 1; k++) {
if(testPapers.get(k).getPaperNumber() > testPapers.get(k+1).getPaperNumber()){
TestPaper testPaper = new TestPaper();
testPaper = testPapers.get(k);
testPapers.set(k,testPapers.get(k+1));
testPapers.set(k+1,testPaper);
}
}
}
//此时需要构建一个类,包含着题目信息,判分信息;(paper)
//理清楚几个变量的关系,认真画图,搞清楚,马上就能解决了;
//首先,对Paper进行排序;
ArrayList<Paper> papers = new ArrayList<>();
for (int j = 0; j < testPapers.size(); j++) {
Paper paper = new Paper(questionsMessages,testPapers.get(j));
papers.add(paper);
}
for (int j = 0; j < papers.size(); j++) {
int score = 0;
for (int k = 0; k < papers.get(j).testPaper.getNumberAndScores().size(); k++) {
score += papers.get(j).testPaper.getNumberAndScores().get(k).getScores();
}
if(score != 100){
System.out.println("alert: full score of test paper"+papers.get(j).testPaper.getPaperNumber()+" is not 100 points");
}
}//测试正确;
//lastPapers是基于答案的信息存储;
ArrayList <LastPaper> lastPapers = new ArrayList<>();
for (int j = 0; j < answerPapers.size(); j++) {
int no = answerPapers.get(j).getPaperNumber();
for (int k = 0; k < papers.size(); k++) {
if(papers.get(k).testPaper.getPaperNumber() == no){
Paper paper = papers.get(k);
LastPaper lastPaper = new LastPaper(paper,answerPapers.get(j));
lastPapers.add(lastPaper);
}
}
}
ArrayList<GetOutPaper>getOutPapers = new ArrayList<>();
//这次只传有用的信息;
for (int j = 0; j < lastPapers.size(); j++) {
lastPapers.get(j).judger();
}
}
}
class AnswerPaper {
private int paperNumber;
private ArrayList<String> answers = new ArrayList<String>();
AnswerPaper(){}
AnswerPaper(int paperNumber, ArrayList<String> answers){
this.paperNumber = paperNumber;
this.answers = answers;
}
public int getPaperNumber() {
return paperNumber;
}
public void setPaperNumber(int paperNumber) {
this.paperNumber = paperNumber;
}
public ArrayList<String> getAnswers() {
return answers;
}
public void setAnswers(ArrayList<String> answers) {
this.answers = answers;
}
}
class GetOutPaper {
//每张最终试卷只有一份判分信息;
TestPaper testPaper = new TestPaper();
//依据判分信息提取题目;
ArrayList<QuestionsMessage>questionsMessages = new ArrayList<>();
AnswerPaper answerPaper = new AnswerPaper();
GetOutPaper(){}
GetOutPaper(TestPaper testPaper,ArrayList<QuestionsMessage> questionsMessages,AnswerPaper answerPaper){
this.questionsMessages = questionsMessages;
this.testPaper = testPaper;
this.answerPaper = answerPaper;
}
void judge(){
}
void show(){
for (int i = 0; i < testPaper.getPaperNumber(); i++) {
System.out.println(questionsMessages.get(i) + "~" + answerPaper.getAnswers().get(i));
}
}
}
class LastPaper {
private Paper paper = new Paper();
private AnswerPaper answerPaper = new AnswerPaper();
private ArrayList<Boolean>judges = new ArrayList<Boolean>();
private int[] scores = {};
LastPaper(){}
LastPaper(Paper paper,AnswerPaper answerPaper){
this.paper = paper;
this.answerPaper = answerPaper;
}
void judger(){
for (int i = 0; i < paper.testPaper.getNumberAndScores().size(); i++) {
int number = paper.testPaper.getNumberAndScores().get(i).getNo();
String standardAnswer = paper.questionsMessages.get(number - 1).getStandardAnswer();
if(i > answerPaper.getAnswers().size()-1){
System.out.println("answer is null");
judges.add(false);
}else{
int num = paper.testPaper.getNumberAndScores().get(i).getNo() - 1;
System.out.print(paper.questionsMessages.get(num).getQuestion() + "~" + answerPaper.getAnswers().get(i));
if(standardAnswer.equals(answerPaper.getAnswers().get(i))){
judges.add(true);
System.out.println("~true");
}else{
judges.add(false);
System.out.println("~false");
}
}
}
for (int i = 0; i < paper.testPaper.getNumberAndScores().size(); i++) {
if(judges.get(i)){
System.out.printf("%d",paper.testPaper.getNumberAndScores().get(i).getScores());
}else{
System.out.print("0");
}
if(i != paper.testPaper.getNumberAndScores().size() - 1){
System.out.print(" ");
}
}
System.out.print("~");
int all = 0;
for (int j = 0; j < judges.size(); j++) {
if(judges.get(j)){
all += paper.testPaper.getNumberAndScores().get(j).getScores();
}
}
System.out.println(all);
}
public Paper getPaper() {
return paper;
}
public void setPaper(Paper paper) {
this.paper = paper;
}
public AnswerPaper getAnswerPaper() {
return answerPaper;
}
public void setAnswerPaper(AnswerPaper answerPaper) {
this.answerPaper = answerPaper;
}
boolean judge(String a, String b){
if(a.equals(b)){
return true;
}else {
return false;
}
}
}
class NumberAndScores {
private int No;
private int scores;
NumberAndScores(){}
NumberAndScores(int No,int scores){
this.No = No;
this.scores = scores;
}
public int getNo() {
return No;
}
public void setNo(int no) {
No = no;
}
public int getScores() {
return scores;
}
public void setScores(int scores) {
this.scores = scores;
}
}
class Paper {
ArrayList<QuestionsMessage> questionsMessages = new ArrayList<QuestionsMessage>();
TestPaper testPaper = new TestPaper();
Paper(){}
Paper(ArrayList<QuestionsMessage>questionsMessages,TestPaper testPaper){
this.questionsMessages = questionsMessages;
this.testPaper =testPaper;
}
}
class QuestionsMessage {
private int No;
private String question;
private String standardAnswer;
private int Score;
QuestionsMessage(){}
QuestionsMessage(int No, String question, String standardAnswer){
this.No = No;
this.question = question;
this.standardAnswer = standardAnswer;
}
public int getScore() {
return Score;
}
public void setScore(int score) {
Score = score;
}
public int getNo() {
return No;
}
public void setNo(int no) {
No = no;
}
public String getQuestion() {
return question;
}
public void setQuestion(String question) {
this.question = question;
}
public String getStandardAnswer() {
return standardAnswer;
}
public void setStandardAnswer(String standardAnswer) {
this.standardAnswer = standardAnswer;
}
}
class TestPaper {
private int paperNumber;
private ArrayList <NumberAndScores>numberAndScores = new ArrayList<NumberAndScores>();
TestPaper(){}
TestPaper(int paperNumber, ArrayList<NumberAndScores>numberAndScores){
this.paperNumber = paperNumber;
this.numberAndScores = numberAndScores;
}
public int getPaperNumber() {
return paperNumber;
}
public void setPaperNumber(int paperNumber) {
this.paperNumber = paperNumber;
}
public ArrayList<NumberAndScores> getNumberAndScores() {
return numberAndScores;
}
public void setNumberAndScores(ArrayList<NumberAndScores> numberAndScores) {
this.numberAndScores = numberAndScores;
}
}
类图
设计
本次设计了七个类:
- NumberAndScores类:用于储存出现的题号和分数;
- QuestionMessages类:用于存储出现的题目的题号、题干、标准答案;
- TestPaper类:用于存储试卷中的题目的题号和分数;
- Paper类:将试卷信息和对应的题目信息整合存储在一起,变成一个整体,在后期判断正确性的时候更加方便;
- AnswerPaper类:用于存储答题信息,包含:试卷号、题号、答案;
- LastPaper类:用于做最后的判断和整合;
- GetOutPaper类:用于最后的输出
设计中出现的问题:
- 类的命名:最后几个类的命名不清晰,导致在最后整合的时候自己都不能清晰讲出每个类的用处,导致代码的可读性和可复用性严重降低;
- 类的设计对于问题的分析不清楚:这种设计对于这个题目存在一定的问题,因为基于答卷进行的判断设计,很难判断最后是否有试卷没有调用的情况。因此,在设计之前,应该重返考虑测试点情况,做到所有情况心中有数之后再开始coding;
- 设计的逻辑仍旧不够清晰,在后期修改的时候造成了一定的困难。
- 对应存储QuestionMessages仍然存在问题,在存储的时候没有按照试卷的顺序存储,导致后期判断存在困难;
-方法的使用存在问题:在LastPaper的judger中实现了太多的功能,匹配、判断、排序,导致judger过于冗长,代码的SRP原则被打破; - 总是在忙于实现,但是没有用充足的时间进行设计,导致到最后实现用了太多的时间,才发现自己的设计存在问题,这是一个错误的开发逻辑,心急吃不了热豆腐;
- 总是在出现问题的时候才开始写注释找问题,这会花费很多的时间,也是不好的习惯。
SourceMonitor测试
从测试结果来看,存在以下问题:
- 首先是main函数中写了太多的功能,字符串的分类、初步处理都放在main函数中了,main函数达到了恐怖的1833行,函数深度过高,SPR的思想不够明确;
- 将大量的处理和分析写进了实体类中,整个系统中缺少专门用来处理的类;
- 本次练习的注释的覆盖度明显高于上一次,提高了代码的可读性;
较于上次的进步:
- 学会运用好ArrayList,在存储的时候方便了许多,但同时的问题是写一些处理时候更加麻烦;
- 这次的难度上升了很多,能不知难而退也是一种磨砺;
设计与分析(第三次)
源码
import java.util.ArrayList;
import java.util.Scanner;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
String[] messages = new String[100];
//定义题目的对象(由于题目比较多,并且不知道数量,采用ArrayList进行存储)
ArrayList<QuestionsMessage> questionsMessages = new ArrayList<QuestionsMessage>();
//定义试卷信息对象
ArrayList<TestPaper>testPapers = new ArrayList<TestPaper>();
//定义答卷对象
ArrayList<AnswerPaper> answerPapers = new ArrayList<AnswerPaper>();
//定义学生信息
ArrayList<Student> students = new ArrayList<>();
ArrayList<Integer> deleteNum = new ArrayList<>();
//首先,输入行数未知,输入结束的标志是“end”
int i = 0;
messages[i] = sc.nextLine();
while(!messages[i].equals("end")){
if(messages[i].matches("#N:\\d+ #Q:(.+) #A(.+)*")){//1
QuestionsMessage questionsMessage = new QuestionsMessage(messages[i]);
questionsMessage.processStr();
questionsMessage.setAppearance(true);
questionsMessages.add(questionsMessage);
} else if (messages[i].matches("^#T:\\d+( \\d+-\\d+)*")) {//2
TestPaper testPaper = new TestPaper(messages[i]);
testPaper.processStr();
testPapers.add(testPaper);
} else if (messages[i].matches("^#S:( )*\\d+( )*\\d+\\s*(.*?)$")) {//3
AnswerPaper answerPaper = new AnswerPaper(messages[i]);
answerPaper.processStr();
answerPapers.add(answerPaper);
} else if (messages[i].matches("#X:\\d+(\\w+ \\w+)+(-\\w+ \\w+)*")) {//4
String[] str1 = messages[i].split("#X:|-");
for (int j = 1; j < str1.length; j++) {
String[] information = str1[j].split(" ");
Student student = new Student(Integer.parseInt(information[0]),information[1]);
students.add(student);
}
} else if (messages[i].matches("#D:N-\\d+")) {
String str = messages[i].replaceAll("#D:N-","");
deleteNum.add(Integer.parseInt(str));
}else{
System.out.println("wrong format:" + messages[i]);
if(messages[i].startsWith("#N:")){
QuestionsMessage questionsMessage = new QuestionsMessage();
questionsMessage.setAppearance(true);
questionsMessages.add(questionsMessage);
}
}
i++;
messages[i] = sc.nextLine();
}//存储完成
//对于被删除的题目的处理;
for (int j = 0; j < deleteNum.size(); j++) {
for (int k = 0; k < questionsMessages.size(); k++) {
if(deleteNum.get(j) == questionsMessages.get(k).getNo()) {
questionsMessages.get(k).setScore(0);//如果有符合的,将分数设为0
questionsMessages.get(k).setNotDelete(false);
}
}
}
//组建Paper类
ArrayList<Paper>papers = new ArrayList<>();
for (int j = 0; j < testPapers.size(); j++) {
//试卷是基于testPaper而产生的类
//有多少个testpaper,就会有多少个Paper
//number与testPaper相同
int number = testPapers.get(j).getPaperNumber();
ArrayList<QuestionsMessage>questionsMessages1 = new ArrayList<>();
//此处需要基于testPaper中题目数量来将题目(questionMessages存入)
//testPaper中题目数量
for (int k = 0; k < testPapers.get(j).getNumberAndScores().size(); k++) {
//题目总数量
for (int l = 0; l < questionsMessages.size(); l++) {
//只要题号相等,就存入
if(questionsMessages.get(l).getNo() == testPapers.get(j).getNumberAndScores().get(k).getNo()) {
questionsMessages1.add(questionsMessages.get(l));
break;
}//试卷中有的题目题库中没有,存入空;
if (l == questionsMessages.size() - 1 && questionsMessages.get(l).getNo() != testPapers.get(j).getNumberAndScores().get(k).getNo()) {
QuestionsMessage questionsMessage = new QuestionsMessage(testPapers.get(j).getNumberAndScores().get(k).getNo(),"","",true,true);
//questionsMessage.setAppearance(true);
questionsMessages1.add(questionsMessage);//要是没有找到对应的题目,传入一个空的questionsMessage
}
}
}
Paper paper = new Paper(number,questionsMessages1,testPapers.get(j));
papers.add(paper);
}//将题目和题号对应了;
for (int j = 1; j <= papers.size(); j++) {
for (int k = 0; k < papers.size(); k++) {
if(papers.get(k).getNumber() == j && !papers.get(k).isFull()){
System.out.println("alert: full score of test paper" + j + " is not 100 points");
}
}
}
//此处有一个错误信息:可能找不到对应的学号;
//还存在:可能找不到对应的试卷号;
//数据存入StudentAnswerPaper
ArrayList<StudentAnswerPaper> studentAnswerPapers = new ArrayList<>();
for (int j = 0; j < answerPapers.size(); j++) {
//定义初始量
int paperNumber = answerPapers.get(j).getPaperNumber();
int studentNumber = answerPapers.get(j).getStudentNumber();
Paper paper = new Paper();
Student student = new Student();
//用于寻找papers中是否有对应的paper;
boolean index1 = false;
if(papers.size() == 0){
System.out.println("The test paper number does not exist");
}
//存入paper
for (int k = 0; k < papers.size(); k++) {
if(papers.get(k).getNumber() == paperNumber){
paper = papers.get(k);
index1 = true;
break;
}else if(k == papers.size() - 1 && papers.get(k).getNumber() != paperNumber){
System.out.println("The test paper number does not exist");
}
}
for (int k = 0; k < students.size(); k++) {
if(studentNumber == students.get(k).getNo()){
student = students.get(k);
break;
} else if (k == students.size() - 1 && studentNumber != student.getNo()) {
student = students.get(k);
student.setFound(false);
}
}
if(index1){
StudentAnswerPaper studentAnswerPaper = new StudentAnswerPaper(paper,answerPapers.get(j),student);
studentAnswerPapers.add(studentAnswerPaper);
}
}
for (int j = 0; j < studentAnswerPapers.size(); j++) {
studentAnswerPapers.get(j).adjust();
}
Agent agent = new Agent(studentAnswerPapers,questionsMessages,deleteNum);
agent.solution();
agent.print();
}
}
class Agent {
private ArrayList<StudentAnswerPaper>studentAnswerPapers = new ArrayList<>();
private ArrayList<QuestionsMessage>questionsMessages = new ArrayList<>();
private ArrayList<Integer> deleteNum = new ArrayList<>();
public Agent() {
}
public Agent(ArrayList<StudentAnswerPaper> studentAnswerPapers,ArrayList<QuestionsMessage>questionsMessages,ArrayList<Integer> deleteNum) {
this.studentAnswerPapers = studentAnswerPapers;
this.questionsMessages = questionsMessages;
this.deleteNum = deleteNum;
}
public void solution(){
//对每套试卷进行遍历;
for (int i = 0; i < studentAnswerPapers.size(); i++) {
//两层循环
//再检索题库中是否有这个题目;
for (int j = 0; j < studentAnswerPapers.get(i).getPaper().getTestPaper().getNumberAndScores().size(); j++) {
for (int k = 0; k < questionsMessages.size(); k++) {
if(studentAnswerPapers.get(i).getPaper().getTestPaper().getNumberAndScores().get(j).getNo() == questionsMessages.get(k).getNo()){
break;
}else if(k == questionsMessages.size() - 1 && studentAnswerPapers.get(i).getPaper().getTestPaper().getNumberAndScores().get(j).getNo() != questionsMessages.get(k).getNo()){
studentAnswerPapers.get(i).getPaper().getTestPaper().getNumberAndScores().get(j).setTip("non-existent question~0");
studentAnswerPapers.get(i).getPaper().getTestPaper().getNumberAndScores().get(j).setJudge(false);
}
}
}
//一层循环
//再判断是否被删除
for (int j = 0; j < studentAnswerPapers.get(i).getPaper().getTestPaper().getNumberAndScores().size(); j++) {
for (int k = 0; k < deleteNum.size(); k++) {
if(deleteNum.get(k) == studentAnswerPapers.get(i).getPaper().getTestPaper().getNumberAndScores().get(j).getNo()){
studentAnswerPapers.get(i).getPaper().getTestPaper().getNumberAndScores().get(j).setTip("the question " + studentAnswerPapers.get(i).getPaper().getTestPaper().getNumberAndScores().get(j).getNo() + " invalid~0");
studentAnswerPapers.get(i).getPaper().getTestPaper().getNumberAndScores().get(j).setJudge(false);
}
}
}
//两层循环
//对于每个题目进行访问;
for (int j = 0; j < studentAnswerPapers.get(i).getPaper().getTestPaper().getNumberAndScores().size(); j++) {
for (int k = 0; k < studentAnswerPapers.get(i).getAnswerPaper().getStuAnswers().size(); k++) {
if(j + 1 == studentAnswerPapers.get(i).getAnswerPaper().getStuAnswers().get(k).getNo()){
break;
}else if(k == studentAnswerPapers.get(i).getAnswerPaper().getStuAnswers().size() - 1 && j + 1 != studentAnswerPapers.get(i).getAnswerPaper().getStuAnswers().get(k).getNo()){
studentAnswerPapers.get(i).getPaper().getTestPaper().getNumberAndScores().get(j).setTip("answer is null");
studentAnswerPapers.get(i).getPaper().getTestPaper().getNumberAndScores().get(j).setJudge(false);
}
}
}
}
}
public void print(){
for (int i = 0; i < studentAnswerPapers.size(); i++) {
if(!studentAnswerPapers.get(i).getAnswerPaper().getStuAnswers().isEmpty()){
for (int j = 0; j < studentAnswerPapers.get(i).getPaper().getTestPaper().getNumberAndScores().size(); j++) {
if(studentAnswerPapers.get(i).getPaper().getTestPaper().getNumberAndScores().get(j).isJudge()){
String answer = "";
//让答题信息和标准答案进行匹配
for (int k = 0; k < studentAnswerPapers.get(i).getAnswerPaper().getStuAnswers().size(); k++) {
if (studentAnswerPapers.get(i).getAnswerPaper().getStuAnswers().get(k).getNo() == j + 1) {
answer = studentAnswerPapers.get(i).getAnswerPaper().getStuAnswers().get(k).getAnswer();
break;
}
}
System.out.println(studentAnswerPapers.get(i).getPaper().getQuestionsMessages().get(j).toString(answer));
}else{
System.out.println(studentAnswerPapers.get(i).getPaper().getTestPaper().getNumberAndScores().get(j).getTip());
}
}
}
//再次对于正确性进行判断
//对于问题信息进行遍历
if(!studentAnswerPapers.get(i).getStudent().isFound()){
System.out.println(studentAnswerPapers.get(i).getAnswerPaper().getStudentNumber() + " not found");//没有这个人
}else {
if (studentAnswerPapers.get(i).getAnswerPaper().getStuAnswers().isEmpty()) {
for (int j = 0; j < studentAnswerPapers.get(i).getPaper().getQuestionsMessages().size(); j++) {
System.out.println("answer is null");
}
for (int j = 0; j < studentAnswerPapers.get(i).getPaper().getQuestionsMessages().size(); j++) {
System.out.print(studentAnswerPapers.get(i).getAnswerPaper().getStudentNumber() + " " + studentAnswerPapers.get(i).getStudent().getName() + ": ");
if (j == studentAnswerPapers.get(i).getPaper().getQuestionsMessages().size() - 1) {
System.out.print(0);
} else {
System.out.print(" 0");
}
System.out.println("~" + "0");
}
} else {
//将总分设定出来;
int all = 0;
//有这个人,就输出相关信息;
System.out.print(studentAnswerPapers.get(i).getAnswerPaper().getStudentNumber() + " " + studentAnswerPapers.get(i).getStudent().getName() + ": ");
//首先,应该对于每一个题目进行判定(有错误信息,直接输出0,不加;没有错误信息,输出对应的分数)
for (int j = 0; j < studentAnswerPapers.get(i).getPaper().getQuestionsMessages().size(); j++) {
if (!studentAnswerPapers.get(i).getPaper().getTestPaper().getNumberAndScores().get(j).isJudge()) {
if (j == studentAnswerPapers.get(i).getPaper().getQuestionsMessages().size() - 1)
System.out.print(0);
else
System.out.print("0 ");
} else {
//寻找题号
for (int k = 0; k < studentAnswerPapers.get(i).getAnswerPaper().getStuAnswers().size(); k++) {
//要是找到了对应题号,停止搜索,并判定正确性
if (j + 1 == studentAnswerPapers.get(i).getAnswerPaper().getStuAnswers().get(k).getNo()) {
if (studentAnswerPapers.get(i).getAnswerPaper().getStuAnswers().get(k).getAnswer().equals(studentAnswerPapers.get(i).getPaper().getQuestionsMessages().get(j).getStandardAnswer())) {
if (j == studentAnswerPapers.get(i).getPaper().getQuestionsMessages().size() - 1)
System.out.print(studentAnswerPapers.get(i).getPaper().getTestPaper().getNumberAndScores().get(j).getScores());
else
System.out.printf("%d ", studentAnswerPapers.get(i).getPaper().getTestPaper().getNumberAndScores().get(j).getScores());
all += studentAnswerPapers.get(i).getPaper().getTestPaper().getNumberAndScores().get(j).getScores();
} else {
if (j == studentAnswerPapers.get(i).getPaper().getQuestionsMessages().size() - 1)
System.out.print(0);
else
System.out.print("0 ");
}
break;
}
}
}
}
System.out.println("~" + all);
}
}
}
}
}
class AnswerPaper {
private String str;
private int paperNumber;
private int studentNumber;
private ArrayList<StuAnswer> stuAnswers = new ArrayList<StuAnswer>();
AnswerPaper(){}
AnswerPaper(int studentNumber,int paperNumber, ArrayList<StuAnswer> stuAnswers){
this.studentNumber = studentNumber;
this.paperNumber = paperNumber;
this.stuAnswers = stuAnswers;
}
AnswerPaper(String str){
this.str = str;
}
public void processStr(){
String[] strs = str.split("#S:|#A:");//str[0] = ""; str[1] = "1 20201103"; str[2] = "1-5"......
String[] numAndStudentNum = strs[1].split(" ");//numAndStudentNum[0] = "1" ;numAndStudentNum[1] = "20201103"
ArrayList<StuAnswer>stuAnswers = new ArrayList<>();
for (int j = 2; j < strs.length ; j++) {
//用“-”对字符串进行分割;
String[] second = strs[j].split("-");
//删除前后
// if(second.length == 2){
// while(second[1].charAt(second[1].length() - 1) == ' '){
// second[1] = second[1].substring(0, second[1].length() - 1);
// }
// }
second[1] = second[1].trim();
//将答题信息存入StuAnswer
if(second.length == 2){
StuAnswer stuAnswer = new StuAnswer(Integer.parseInt(second[0]),second[1]);
stuAnswers.add(stuAnswer);
}else{
StuAnswer stuAnswer = new StuAnswer(Integer.parseInt(second[0]),"");
stuAnswers.add(stuAnswer);
}
}
this.studentNumber = Integer.parseInt(numAndStudentNum[1]);
this.paperNumber = Integer.parseInt(numAndStudentNum[0]);
this.stuAnswers = stuAnswers;
}
public int getStudentNumber() {
return studentNumber;
}
public void setStudentNumber(int studentNumber) {
this.studentNumber = studentNumber;
}
public int getPaperNumber() {
return paperNumber;
}
public void setPaperNumber(int paperNumber) {
this.paperNumber = paperNumber;
}
public ArrayList<StuAnswer> getStuAnswers() {
return stuAnswers;
}
public void setStuAnswers(ArrayList<StuAnswer> stuAnswers) {
this.stuAnswers = stuAnswers;
}
}
class StuAnswer {
private int no;
private String answer;
StuAnswer(){}
StuAnswer(int no,String answer){
this.no = no;
this.answer = answer;
}
public int getNo() {
return no;
}
public void setNo(int no) {
this.no = no;
}
public String getAnswer() {
return answer;
}
public void setAnswer(String answer) {
this.answer = answer;
}
}
class Paper {
private int number;//试卷号
private ArrayList<QuestionsMessage> questionsMessages = new ArrayList<>();//对应的题目
private TestPaper testPaper;
Paper (){}
Paper(int number,ArrayList<QuestionsMessage>questionsMessages,TestPaper testPaper){
this.number = number;
this.questionsMessages = questionsMessages;
this.testPaper = testPaper;
}
public int allScores(){
int all = 0;
for (int i = 0; i < questionsMessages.size(); i++) {
if(questionsMessages.get(i).isCorrct())
all += testPaper.getNumberAndScores().get(i).getScores();
}
return all;
}
public boolean isFull(){
int all = 0;
for (int i = 0; i < questionsMessages.size(); i++) {
all+=questionsMessages.get(i).getScore();
}
if(all == 100){
return true;
}else{
return false;
}
}
public int getNumber() {
return number;
}
public void setNumber(int number) {
this.number = number;
}
public ArrayList<QuestionsMessage> getQuestionsMessages() {
return questionsMessages;
}
public void setQuestionsMessages(ArrayList<QuestionsMessage> questionsMessages) {
this.questionsMessages = questionsMessages;
}
public TestPaper getTestPaper() {
return testPaper;
}
public void setTestPaper(TestPaper testPaper) {
this.testPaper = testPaper;
}
}
class QuestionsMessage {
private String str;
private int No = 0;
private String question = "";
private String standardAnswer;
private int Score = 0;
private boolean notDelete = true;
private boolean Corrct = false;
private boolean isempty = false;
//题目是否出现过;
private boolean appearance = false;
QuestionsMessage(){}
QuestionsMessage(int No, String question, String standardAnswer,Boolean isempty,Boolean appearance){
this.No = No;
this.question = question;
this.standardAnswer = standardAnswer;
this.isempty = isempty;
this.appearance = appearance;
}
QuestionsMessage(String str){
this.str = str;
}
public void processStr(){
//第一步:筛选题目编号
String regex ="#N:(.*?)\\s#Q:";
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(str);//定义查找的相关类
int number = 0;
if(matcher.find()){
number = Integer.parseInt(matcher.group(1));
}
//第二步,筛选题目类容;
regex = "#Q:(.*?)\\s#A:";
pattern = Pattern.compile(regex);
matcher = pattern.matcher(str);
String text = "";
if(matcher.find()){
text = matcher.group(1);
}
//第三步,筛选标准答案;
regex = "#A:(.*?)$";//这个正则表达式需要二次检查;
pattern = Pattern.compile(regex);
matcher = pattern.matcher(str);
String answer = "";
if(matcher.find()){
answer = matcher.group(1);
}
answer = answer.trim();//删除前后空格
text = text.trim();//删除前后空格
this.No = number;
this.question = text;
this.standardAnswer = answer;
}
public void judge(String answer){
if(notDelete){
if(answer.equals(this.standardAnswer)){
this.Corrct = true;
} else{
this.Corrct = false;
}
}
}
public String toString(String answer){
judge(answer);
if(this.standardAnswer.equals(answer)){
return this.question + "~" + answer + "~" + Corrct;
}else{
return this.question + "~" + answer + "~" + Corrct;
}
}
public String getStr() {
return str;
}
public void setStr(String str) {
this.str = str;
}
public boolean isCorrct() {
return Corrct;
}
public void setCorrct(boolean corrct) {
Corrct = corrct;
}
public boolean isIsempty() {
return isempty;
}
public void setIsempty(boolean isempty) {
this.isempty = isempty;
}
public boolean isAppearance() {
return appearance;
}
public void setAppearance(boolean appearance) {
this.appearance = appearance;
}
public boolean isNotDelete() {
return notDelete;
}
public void setNotDelete(boolean notDelete) {
this.notDelete = notDelete;
}
public int getScore() {
return Score;
}
public void setScore(int score) {
Score = score;
}
public int getNo() {
return No;
}
public void setNo(int no) {
No = no;
}
public String getQuestion() {
return question;
}
public void setQuestion(String question) {
this.question = question;
}
public String getStandardAnswer() {
return standardAnswer;
}
public void setStandardAnswer(String standardAnswer) {
this.standardAnswer = standardAnswer;
}
}
class Student {
private int no;
private String name;
private boolean found = true;
Student(){}
Student(int no,String name){
this.name = name;
this.no = no;
}
public boolean isFound() {
return found;
}
public void setFound(boolean found) {
this.found = found;
}
public int getNo() {
return no;
}
public void setNo(int no) {
this.no = no;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
class StudentAnswerPaper {
private Student student;
private Paper paper;
private AnswerPaper answerPaper;
StudentAnswerPaper(){}
StudentAnswerPaper(Paper paper,AnswerPaper answerPaper,Student student){
this.paper = paper;
this.answerPaper = answerPaper;
this.student = student;
}
public void adjust(){
for (int i = 0; i < answerPaper.getStuAnswers().size(); i++) {
for (int j = 0; j < answerPaper.getStuAnswers().size() - i - 1; j++) {
if(answerPaper.getStuAnswers().get(j).getNo() > answerPaper.getStuAnswers().get(j + 1).getNo()){
StuAnswer stuAnswer = new StuAnswer();
int no1 = answerPaper.getStuAnswers().get(j).getNo();
String answer1 = answerPaper.getStuAnswers().get(j).getAnswer();
int no2 = answerPaper.getStuAnswers().get(j + 1).getNo();
String answer2 = answerPaper.getStuAnswers().get(j + 1).getAnswer();
answerPaper.getStuAnswers().get(j).setNo(no2);
answerPaper.getStuAnswers().get(j).setAnswer(answer2);
answerPaper.getStuAnswers().get(j + 1).setNo(no1);
answerPaper.getStuAnswers().get(j + 1).setAnswer(answer1);
}
}
}
}
public Student getStudent() {
return student;
}
public void setStudent(Student student) {
this.student = student;
}
public Paper getPaper() {
return paper;
}
public void setPaper(Paper paper) {
this.paper = paper;
}
public AnswerPaper getAnswerPaper() {
return answerPaper;
}
public void setAnswerPaper(AnswerPaper answerPaper) {
this.answerPaper = answerPaper;
}
}
class TestPaper {
private String str;
private int paperNumber;
private ArrayList <Scores> scores = new ArrayList<Scores>();
TestPaper(){}
TestPaper(int paperNumber, ArrayList<Scores> scores){
this.paperNumber = paperNumber;
this.scores = scores;
}
TestPaper(String str){
this.str = str;
}
public void processStr(){
//第一步:储存试卷号
String regex = "#T:(.*?)\\s\\d";
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(str);//定义查找的相关类
int paperNumber = 0;
if(matcher.find()){
paperNumber = Integer.parseInt(matcher.group(1));
}
//第二步:将题目和分数以字符串的形式存储;(同时注意:编号0是不需要处理的)
String[] NOAndScores = str.split(" ");
//定义NumberAndScores ArrayList进行存储;
ArrayList<Scores> scores = new ArrayList<Scores>();
for (int j = 1; j < NOAndScores.length; j++) {
String[] NoScores = NOAndScores[j].split("-");
int No = Integer.parseInt(NoScores[0]);
int score = Integer.parseInt(NoScores[1]);
Scores scores1 = new Scores(No,score);
scores.add(scores1);
}
this.paperNumber = paperNumber;
this.scores = scores;
}
public int getPaperNumber() {
return paperNumber;
}
public void setPaperNumber(int paperNumber) {
this.paperNumber = paperNumber;
}
public ArrayList<Scores> getNumberAndScores() {
return scores;
}
public void setNumberAndScores(ArrayList<Scores> scores) {
this.scores = scores;
}
}
class Scores {
private int No;
private int scores;
private String tip = "";//用于存储错误信息;
private boolean judge = true;
Scores(){}
Scores(int No, int scores){
this.No = No;
this.scores = scores;
}
public String getTip() {
return tip;
}
public void setTip(String tip) {
this.tip = tip;
}
public boolean isJudge() {
return judge;
}
public void setJudge(boolean judge) {
this.judge = judge;
}
public int getNo() {
return No;
}
public void setNo(int no) {
No = no;
}
public int getScores() {
return scores;
}
public void setScores(int scores) {
this.scores = scores;
}
}
类图
设计
本次设计九个类:
- StuAnswer:用于学生的一个答案和对应题号;
- AnswerPaper:每有一个学生的答题信息,生成一个,并且存储该学生的学号、答的试卷、答的题号、答案信息;
- QuestionMessages:用于存储输入的题目信息;
- Scores:用于存储试卷每个题目的赋分情况;
- TestPaper:用于存储每张试卷的试卷号,试卷引用题目及其分数;
- Paper:基于每一张试卷,组装试卷的QuestionMessages、TestPaper和试卷号;
- Student:存储学生学号和姓名
- StudentAnswerPaper:基于答题信息,组织相应的Paper、student;
- Agent:完成最后的错误信息审定、判分和输出
设计中出现的问题:
- 基于SRP原则,Agent的函数solution任然存在大量的代码可以进行进一步分解;
- 最初的设计仍然会出现问题:在于当某一个题目出现多次回答的时候,判断不会出错,但是在统计总分的时候,第二次的正确性会对第一次的正确性进行覆盖,因此如果按照第一次的判分结果进行统计分数会出错。因此,我的解决方案是重新进行判定,而这一定产生了大量的冗余代码,但是在这个架构下没有办法解决这个问题。因此,本次设计依然存在问题;
- 依然在主函数中加入了大量的判断,没有在根本上解决主函数复杂性的问题;
- 一开始并没有对题意有充分的解读,导致最初的大量判分设计都存在着根本上的错误,导致浪费了大量的实践,没有充分的时间将代码修改到满分;
SourceManager分析:
通过分析结果,存在以下问题:
- Agent类中函数还是过于复杂,几个函数的职责还是没有完全分清,又因为存在覆盖问题,在输出的时候重新的题目进行判断,形成了职责的交叉,这固然是存在问题的;
- Main函数还是存在大量代码,虽然已经将大量的代码放进函数中,但是由于正则表达式的应用和大量的if—else语句兼并很多错误信息的输出,main函数中还是复杂度大增,这可能是后期仍然需要解决的问题;
较于上次的进步:
- 能够根据答卷给与的顺序填入题目,非常合理的解决了后期的判分顺序问题,解决了大量的代码复杂度;
- 写入大量的注释,大大增加了代码的可读性;
- 代码的清晰度于心之中有了更加清晰的认识,对于自己的代码更加熟悉,修改更加得心应手;
- 虽然样例都通过,但是还是没得到高分的时候,不停的尝试,改正了无数的错误,也是没有放弃,也是耐心上的新进步;
踩坑心得:
- 设计的重要性:
最初的设计问题导致case17实际上是没有办法通过的,再次强调了开始写之前阅读所有测试样例的重要性;
- 多考虑特殊情况:
在这个题目中,因为一条错误信息的没有输出,导致好几个点根本没有通过的机会。这也是后期要考虑周全的,一定要理清错误信息的关系。
改进建议:
- 对于我来说,完成三次PTA最大的心得在于一定要做好设计再进行coding
- 阅读完所有的测定样例后再开始设计;
- 在设计的时候,尽量将类的用处分的更细,来完成SRP;
- 一边写代码一边进行注释可以让你后期的修改更加得心应手;
- 运用不同的容器、了解不同容器的性质可以让数据存储更加合理;
- 尽量让主函数的代码量降低,降低主函数的复杂度可以在迭代的时候改动更小;
总结
知识点:
类的设计
类与对象
JAVA的语法知识
MVC模式和SRP(SingleResponsibilitiesPrinciple)原则
数组、链表的考察
建议和意见:
- 希望PTA的测试点的描述能够更加清晰一点,测试样例覆盖更广的特殊情况,能够增强我们学生的效率;
- 希望能够稍微延长PTA的时限,让学生能更加合理分配自己的时间;