一.前言
经过了第二轮4-6周的面向对象程序设计的学习,我对于这门课程的理解又更进一步。如同老师所说的,这门课程学下来,你会发现真正困难的从来不是敲代码的部分,而应当时设计的部分。在看到一道题之后第一时间想到不再是直接写代码,而是认真的反复查阅,构思一幅逻辑完整且正确的类图,它应当遵循面向对象程序的多项原则,同时可以使用多种模式进行我们需求的满足。这三周的题目集在前三周的基础上做出了迭代和改动,但是题目的思考不到位且投入的时间不足,故而没有取得一个合适的成绩。
二.设计与分析
*1.PTA第四次习题集
1、题目信息
题目信息为独行输入,一行为一道题,多道题可分多行输入。
程序输入信息分五种,信息可能会打乱顺序混合输入。
格式:"#N:"+题目编号+" "+"#Q:"+题目内容+" "#A:"+标准答案
格式约束:
1、题目的输入顺序与题号不相关,不一定按题号顺序从小到大输入。
2、允许题目编号有缺失,例如:所有输入的题号为1、2、5,缺少其中的3号题。此种情况视为正常。
样例:#N:1 #Q:1+1= #A:2
#N:2 #Q:2+2= #A:4
2、试卷信息
试卷信息为独行输入,一行为一张试卷,多张卷可分多行输入数据。 \
格式:"#T:"+试卷号+" "+题目编号+"-"+题目分值+" "+题目编号+"-"+题目分值+...
格式约束:
题目编号应与题目信息中的编号对应。
一行信息中可有多项题目编号与分值。
样例:#T:1 3-5 4-8 5-2
3、学生信息
学生信息只输入一行,一行中包括所有学生的信息,每个学生的信息包括学号和姓名,格式如下。
格式:"#X:"+学号+" "+姓名+"-"+学号+" "+姓名....+"-"+学号+" "+姓名
格式约束:
答案数量可以不等于试卷信息中题目的数量,没有答案的题目计0分,多余的答案直接忽略,答案之间以英文空格分隔。
样例:
#S:1 #A:5 #A:22
1是试卷号
5是1号试卷的顺序第1题的题目答案
4、答卷信息
答卷信息按行输入,每一行为一张答卷的答案,每组答案包含某个试卷信息中的题目的解题答案,答案的顺序号与试 卷信息中的题目顺序相对应。答卷中:
格式:"#S:"+试卷号+" "+学号+" "+"#A:"+试卷题目的顺序号+"-"+答案内容+...
格式约束:
答案数量可以不等于试卷信息中题目的数量,没有答案的题目计0分,多余的答案直接忽略,答案之间以英文空格分隔。
答案内容可以为空,即””。
答案内容中如果首尾有多余的空格,应去除后再进行判断。
答卷信息中仅包含试卷号、学号,而没有后续内容的,视为一张空白卷,为有效信息,不做格式错误处理。
样例:
#T:1 1-5 3-2 2-5 6-9 4-10 7-3
#S:1 20201103 #A:2-5 #A:6-4
1是试卷号
20201103是学号
2-5中的2是试卷中顺序号,5是试卷第2题的答案,即T中3-2的答案
6-4中的6是试卷中顺序号,4是试卷第6题的答案,即T中7-3的答案
注意:不要混淆顺序号与题号
5、删除题目信息
删除题目信息为独行输入,每一行为一条删除信息,多条删除信息可分多行输入。该信息用于删除一道题目信息,题目被删除之后,引用该题目的试卷依然有效,但被删除的题目将以0分计,同时在输出答案时,题目内容与答案改为一条失效提示,例如:“the question 2 invalid~0”
格式:"#D:N-"+题目号
格式约束:
题目号与第一项”题目信息”中的题号相对应,不是试卷中的题目顺序号。
本题暂不考虑删除的题号不存在的情况。
样例:
#N:1 #Q:1+1= #A:2
#N:2 #Q:2+2= #A:4
#T:1 1-5 2-8
#X:20201103 Tom-20201104 Jack
#S:1 20201103 #A:1-5 #A:2-4
#D:N-2
end
输出结果如下所示:
alert: full score of test paper1 is not 100 points
1+1=~ 5 ~false
the question 2 invalid~0
20201103 Tom: 0 0~0‘
答题信息以一行"end"标记结束,"end"之后的信息忽略。
输出格式:
1、试卷总分警示
该部分仅当一张试卷的总分分值不等于100分时作提示之用,试卷依然属于正常试卷,可用于后面的答题。如果总分等于100 分,该部分忽略,不输出。
格式:"alert: full score of test paper"+试卷号+" is not 100 points"
约束:有多张试卷时,按输入信息的先后顺序输出警示。
样例:alert: full score of test paper2 is not 100 points
2、答卷信息
一行为一道题的答题信息,根据试卷的题目的数量输出多行数据。
格式:题目内容+""+答案++""+判题结果(true/false)
约束:如果输入的答案信息少于试卷的题目数量,每一个缺失答案的题目都要输出"answer is null" 。
样例:
answer is null
3+2=~5~true
4+6=~22~false.
answer is null
3、判分信息
判分信息为一行数据,是一条答题记录所对应试卷的每道小题的计分以及总分,计分输出的先后顺序与题目题号相对应。
格式:学号+" "+姓名+": "+题目得分+" "+....+题目得分+"~"+总分
格式约束:
1、没有输入答案的题目、被删除的题目、答案错误的题目计0分
2、判题信息的顺序与输入答题信息中的顺序相同
样例:20201103 Tom: 0 0~0
根据输入的答卷的数量以上2、3项答卷信息与判分信息将重复输出。
4、被删除的题目提示信息
当某题目被试卷引用,同时被删除时,答案中输出提示信息。样例见第5种输入信息“删除题目信息”。
5、题目引用错误提示信息
试卷错误地引用了一道不存在题号的试题,在输出学生答案时,提示”non-existent question~”加答案。例如:
输入:
#N:1 #Q:1+1= #A:2
#T:1 3-8
#X:20201103 Tom-20201104 Jack-20201105 Www
#S:1 20201103 #A:1-4
end
输出:
alert: full score of test paper1 is not 100 points
non-existent question~0
20201103 Tom: 0~0
如果答案输出时,一道题目同时出现答案不存在、引用错误题号、题目被删除,只提示一种信息,答案不存在的优先级最高,例如:
输入:
#N:1 #Q:1+1= #A:2
#T:1 3-8
#X:20201103 Tom-20201104 Jack-20201105 Www
#S:1 20201103
end
输出:
alert: full score of test paper1 is not 100 points
answer is null
20201103 Tom: 0~0
6、格式错误提示信息
输入信息只要不符合格式要求,均输出”wrong format:”+信息内容。
例如:wrong format:2 #Q:2+2= #4
7、试卷号引用错误提示输出
如果答卷信息中试卷的编号找不到,则输出the test paper number does not exist,答卷中的答案不用输出,参见样例8。
8、学号引用错误提示信息
如果答卷中的学号信息不在学生列表中,答案照常输出,判分时提示错误。参见样例9。
我的部分代码如下:
class InputDeal {
private ArrayList<String> lines = new ArrayList<>();
private ArrayList<String> lineN = new ArrayList<>();
private ArrayList<String> lineT = new ArrayList<>();
private ArrayList<String> lineS = new ArrayList<>();
private String lineX;
private String lineD;
public InputDeal() {
}
public InputDeal(ArrayList<String> lines) {
this.lines = lines;
}
public String getLineD() {
return lineD;
}
public String getLineX() {
return lineX;
}
public ArrayList<Question> NDeal() {
ArrayList<Question> questions = new ArrayList<>();
for (int i = 0; i < lines.size(); i++) {
if (lines.get(i).contains("#N:") || lines.get(i).contains("#Z:") || lines.get(i).contains("#K:")) {
if (judgeN(lines.get(i))) {
lineN.add(lines.get(i));
} else {
System.out.println("wrong format:" + lines.get(i));
}
}
}
if(lineN != null){
for (int i = 0; i < lineN.size(); i++) {
if(lineN.get(i).contains("#N:")){
String[] parts = lineN.get(i).split("#N:|#Q:|#A:");
ArrayList<String> newParts = new ArrayList<>();
for(int j = 0;j < parts.length;j++){
if(!parts[j].isEmpty()) {
newParts.add(parts[j]);
}
}
/*if(parts.length == 3){
newParts.add("");
}*/
Question single = new Single(Integer.parseInt(newParts.get(0).trim()), newParts.get(1).trim(), newParts.get(2).trim());
questions.add(single);
}else if(lineN.get(i).contains("#Z:")){
String[] parts = lineN.get(i).split("#Z:|#Q:|#A:");
ArrayList<String> newParts = new ArrayList<>();
for(int j = 0;j < parts.length;j++){
if(!parts[j].isEmpty()) {
newParts.add(parts[j]);
}
}
Question multiChoice = new MultiChoice(Integer.parseInt(newParts.get(0).trim()), newParts.get(1).trim(), newParts.get(2).trim());
/*if(parts.length == 3){
newParts.add("");
}*/
questions.add(multiChoice);
}else if(lineN.get(i).contains("#K:")){
String[] parts = lineN.get(i).split("#K:|#Q:|#A:");
ArrayList<String> newParts = new ArrayList<>();
for(int j = 0;j < parts.length;j++){
if(!parts[j].isEmpty()) {
newParts.add(parts[j]);
}
}
/*if(parts.length == 3){
newParts.add("");
}*/
Question fillBlank = new FillBlank(Integer.parseInt(newParts.get(0).trim()), newParts.get(1).trim(), newParts.get(2));
questions.add(fillBlank);
}
}
}
return questions;
}
public ArrayList<Test> TDeal() {
ArrayList<Test> tests = new ArrayList<>();
for (int i = 0; i < lines.size(); i++) {
if (lines.get(i).contains("#T:")) {
if (judgeT(lines.get(i))) {
lineT.add(lines.get(i));
} else {
System.out.println("wrong format:" + lines.get(i));
}
}
}
if(lineT != null){
for (int i = 0; i < lineT.size(); i++) {
String[] parts = lineT.get(i).split("#T:|\\s+|-");
ArrayList<String> nunOfQuestions = new ArrayList<>();
ArrayList<String> scoreOfQuestions = new ArrayList<>();
for (int j = 0; j < (parts.length - 2) / 2; j++) {
nunOfQuestions.add(parts[(j + 1) * 2].trim());
scoreOfQuestions.add(parts[(j + 1) * 2 + 1].trim());
}
tests.add(new Test(Integer.parseInt(parts[1].trim()), nunOfQuestions, scoreOfQuestions));
}}
return tests;
}
public ArrayList<Answer> SDeal() {
ArrayList<Answer> answers = new ArrayList<>();
for (int i = 0; i < lines.size(); i++) {
if (lines.get(i).contains("#S:")) {
if (judgeS(lines.get(i))) {
lineS.add(lines.get(i));
} else {
System.out.println("wrong format:" + lines.get(i));
}
}
}
if(lineS != null){
for(int i = 0;i < lineS.size();i++){
String[] parts = lineS.get(i).split("#S:|#A:|-");
String[] parts1 = parts[1].split(" ");
ArrayList<String> nunOfTests = new ArrayList<>();
ArrayList<String> answersOfQuestions = new ArrayList<>();
ArrayList<String> newParts = new ArrayList<>();
for (int j = 0; j < parts.length; j++) {
if (!parts[j].isEmpty()) {
newParts.add(parts[j]);
}
}
for (int j = 1; j < newParts.size(); j = j + 2) {
nunOfTests.add(newParts.get(j).trim());
answersOfQuestions.add(newParts.get(j + 1).stripTrailing());
}
//if(newParts.size() % 2 != 1){
// newParts.add("");
//}
answers.add(new Answer(Integer.parseInt(parts1[0].trim()), parts1[1].trim(), nunOfTests, answersOfQuestions));
}}
return answers;
}
public ArrayList<Student> XDeal() {
ArrayList<Student> students = new ArrayList<>();
for (int i = 0; i < lines.size(); i++) {
if (lines.get(i).contains("#X:")) {
if (judgeX(lines.get(i))) {
lineX = lines.get(i);
} else {
System.out.println("wrong format:" + lines.get(i));
}
}
}
if(lineX != null) {
String[] parts = lineX.split("\\s+|-|#X:");
ArrayList<String> newParts = new ArrayList<>();
for (String part : parts) {
if (!part.isEmpty())
newParts.add(part);
}
for (int i = 0; i < newParts.size(); i = i + 2) {
students.add(new Student(newParts.get(i), newParts.get(i+1)));
}
}
return students;
}
public int numOfD() {
int num = 0;
String regex = "\\d+";
Pattern pattern = Pattern.compile(regex);
for (int i = 0; i < lines.size(); i++) {
if (lines.get(i).contains("#D:")) {
Matcher matcher = pattern.matcher(lines.get(i));
if (matcher.find()) {
num = Integer.parseInt(matcher.group());
}
}
}
return num;
}
public boolean judgeN(String line) {
String regex1 = "#N:\\d+ #Q:(.+) #A:(.+)*";
String regex2 = "#Z:\\d+ #Q:(.+) #A:(.+)*";
String regex3 = "#K:\\d+ #Q:(.+) #A:(.+)*";
Pattern pattern1 = Pattern.compile(regex1);
Pattern pattern2 = Pattern.compile(regex2);
Pattern pattern3 = Pattern.compile(regex3);
Matcher matcher1 = pattern1.matcher(line);
Matcher matcher2 = pattern2.matcher(line);
Matcher matcher3 = pattern3.matcher(line);
if (matcher1.matches() || matcher2.matches() ||matcher3.matches()) {
return true;
}
return false;
}
public boolean judgeT(String line) {
String regex = "#T:\\d+( \\d+-\\d+)+";
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(line);
if (matcher.matches()) {
return true;
}
return false;
}
public boolean judgeX(String line) {
String regex = "#X:\\d+ (\\w+\\w+)+(-\\w+ \\w+)*";
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(line);
if (matcher.matches()) {
return true;
}
return false;
}
public boolean judgeS(String line) {
String regex1 = "#S:\\d+ \\w+( #A:\\w+-(.*)*)*";
String regex2 = "#S:\\d+ \\w+( #A:)*";
String regex3 = "#S:\\d+ \\w+";
String regex4 = "#S:\\d+ \\w+( #A:\\s)*";
Pattern pattern1 = Pattern.compile(regex1);
Pattern pattern2 = Pattern.compile(regex2);
Pattern pattern3 = Pattern.compile(regex3);
Pattern pattern4 = Pattern.compile(regex4);
Matcher matcher1 = pattern1.matcher(line);
Matcher matcher2 = pattern2.matcher(line);
Matcher matcher3 = pattern3.matcher(line);
Matcher matcher4 = pattern4.matcher(line);
if (matcher1.matches() || matcher2.matches() || matcher3.matches() || matcher4.matches()) {
return true;
}
return false;
}
public boolean judgeD(String line) {
String regex = "#D:N-\\d+";
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(line);
if (matcher.matches()) {
return true;
}
return false;
}
}
试卷类,答卷类,学生类都与之前题目集并无过多区别
删除类
class Delete {
private int deleteOfQuestion = 0;
public Delete() {
}
public Delete(int deleteOfQuestion) {
this.deleteOfQuestion = deleteOfQuestion;
}
public int getDeleteOfQuestion() {
return deleteOfQuestion;
}
public void setDeleteOfQuestion(int deleteOfQuestion) {
this.deleteOfQuestion = deleteOfQuestion;
}
}
中介类
class Agent {
private ArrayList<Question> questions;
private ArrayList<Test> tests;
private ArrayList<Answer> answers;
private ArrayList<Student> students;
private Delete delete;
private InputDeal inputDeal;
public Agent() {
}
public Agent(ArrayList<Question> questions, ArrayList<Test> tests, ArrayList<Answer> answers, ArrayList<Student> students, InputDeal inputDeal) {
this.questions = questions;
this.tests = tests;
this.students = students;
this.answers = answers;
this.inputDeal = inputDeal;
}
public ArrayList<Question> getQuestions() {
return questions;
}
public void setQuestions(ArrayList<Question> questions) {
this.questions = questions;
}
public ArrayList<Test> getTests() {
return tests;
}
public void setTests(ArrayList<Test> tests) {
this.tests = tests;
}
public ArrayList<Answer> getAnswers() {
return answers;
}
public void setAnswers(ArrayList<Answer> answers) {
this.answers = answers;
}
public ArrayList<Student> getStudents() {
return students;
}
public void setStudents(ArrayList<Student> students) {
this.students = students;
}
public void numOfDeletion() {
delete = new Delete(inputDeal.numOfD());
}
public boolean fullScore(int idOfTest) {//第idOfTest张试卷是否总分为100
int sum = 0;
for (int i = 0; i < tests.get(idOfTest).getNumOfQuestions().size(); i++) {
sum += Integer.parseInt(tests.get(idOfTest).getScoreOfQuestions().get(i));
}
if (sum != 100) {
return false;
}
return true;
}
public void printFullScore() {
for (int i = 0; i < tests.size(); i++) {
if (!fullScore(i)) {
System.out.println("alert: full score of test paper" + tests.get(i).getIdOfScore() + " is not 100 points");
}
}
}
public boolean testExist(int num) {//判断第num张答案是否有对应的试卷
boolean is = false;
for (int i = 0; i < tests.size(); i++) {
if (answers.get(num).getNum() == tests.get(i).getIdOfScore()) {
is = true;
}
}
return is;
}
public void sortTests() {
int sizeOfTests = tests.size();
for (int i = 0; i < sizeOfTests - 1; i++) {
for (int j = 0; j < sizeOfTests - i - 1; j++) {
if (tests.get(j).getIdOfScore() > tests.get(j + 1).getIdOfScore()) {
Test temp = tests.get(j);
tests.set(j, tests.get(j + 1));
tests.set(j + 1, temp);
}
}
}
}
public void sortAllAnswers(){
int sizeOfAnswers = answers.size();
for (int i = 0; i < sizeOfAnswers - 1; i++) {
for (int j = 0; j < sizeOfAnswers - i - 1; j++) {
if (answers.get(j).getNum() > answers.get(j + 1).getNum()){
Answer temp = answers.get(j);
answers.set(j,answers.get(j + 1));
answers.set(j + 1,temp);
}
}
}
}
public void sortID(){
int sizeOfAnswers = answers.size();
for (int i = 0; i < sizeOfAnswers - 1; i++) {
for (int j = 0; j < sizeOfAnswers - i - 1; j++) {
if (Integer.parseInt(answers.get(j).getID()) > Integer.parseInt(answers.get(j + 1).getID())){
Answer temp = answers.get(j);
answers.set(j,answers.get(j + 1));
answers.set(j + 1,temp);
}
}
}
}
public void sortAnswers(int num) {
int sizeOfAnswers = answers.get(num).getNumOfTests().size();
for (int i = 0; i < sizeOfAnswers - 1; i++) {
for (int j = 0; j < sizeOfAnswers - i - 1; j++) {
if (Integer.parseInt(answers.get(i).getNumOfTests().get(j)) > Integer.parseInt(answers.get(i).getNumOfTests().get(j + 1))) {
String numOfTest = answers.get(i).getNumOfTests().get(j);
answers.get(i).getNumOfTests().set(j, answers.get(i).getNumOfTests().get(j + 1));
answers.get(i).getNumOfTests().set(j + 1, numOfTest);
String numOfAnswer = answers.get(i).getAnswerOfTests().get(j);
answers.get(i).getAnswerOfTests().set(j, answers.get(i).getAnswerOfTests().get(j + 1));
answers.get(i).getAnswerOfTests().set(j + 1, numOfAnswer);
}
}
}
}
public boolean existOfQuestion(int numOfQuestion){
boolean is = false;
for(int i = 0;i < questions.size();i++){
if(numOfQuestion == questions.get(i).getIdOfQuestion()){
is = true;
break;
}
}
return is;
}
public void display() {
printFullScore();
numOfDeletion();
sortAllAnswers();
sortID();
sortTests();
for (int i = 0; i < answers.size(); i++) {
ArrayList<Integer> scores = new ArrayList<>();
if (!testExist(i)) {//判断这个答卷有对应的试卷
System.out.println("The test paper number does not exist");
continue;
}
// sortAnswers(i);//排序answer中的numOfAnswer
int idOfAnswer = answers.get(i).getNum();
int labelOfTest = 0;
for (int j = 0; j < tests.size(); j++) {
if (idOfAnswer == tests.get(j).getIdOfScore()) {
labelOfTest = j;
}
}
int sizeOfTest = tests.get(labelOfTest).getNumOfQuestions().size();
for (int j = 0; j < sizeOfTest; j++) {
String answer =null;
String content = null;
String standAnswer = null;
if (answers.get(i).getNumOfTests().contains(Integer.toString(j + 1))) {
if(delete.getDeleteOfQuestion() != Integer.parseInt(tests.get(labelOfTest).getNumOfQuestions().get(j))) {
if(existOfQuestion(Integer.parseInt(tests.get(labelOfTest).getNumOfQuestions().get(j)))) {
for(int l = 0; l < answers.get(i).getAnswerOfTests().size(); l++) {
if(Integer.parseInt(answers.get(i).getNumOfTests().get(l)) == (j+1) ){
answer = answers.get(i).getAnswerOfTests().get(l);
}
}
int numOfQuestion = 0;
for (int l = 0; l < questions.size(); l++) {//用来获取与试卷num序号对应的question的内容和标准答案
if ((Integer.parseInt(tests.get(labelOfTest).getNumOfQuestions().get(j))) == questions.get(l).getIdOfQuestion()) {
content = questions.get(l).getContent();
standAnswer = questions.get(l).getStandAnswer();
numOfQuestion = l;
}
}
if (judge(answer, questions.get(numOfQuestion)).equals("true")) {
scores.add(Integer.parseInt(tests.get(labelOfTest).getScoreOfQuestions().get(j)));
}else if(judge(answer, questions.get(numOfQuestion)).equals("partially correct")){
int score = Integer.parseInt(tests.get(labelOfTest).getScoreOfQuestions().get(j)) / 2;
scores.add(score);
} else {
scores.add(0);
}
System.out.println(content + "~" + answer + "~" + judge(answer, questions.get(numOfQuestion)));
}else{
System.out.println("non-existent question~0");
scores.add(0);
}
}else{
System.out.println("the question " + delete.getDeleteOfQuestion() +" invalid~0");
scores.add(0);
}
} else {
scores.add(0);
System.out.println("answer is null");
}
}
//算分数汇总
countScore(scores, i);
}
}
public void countScore(ArrayList<Integer> scores, int i) {
int sizeOfScores = scores.size();
int sumOfScores = 0;
for (int j = 0; j < sizeOfScores; j++) {
sumOfScores += scores.get(j);
}
String idOfStudent = answers.get(i).getID();
String nameOfStudent = null;
for (int j = 0; j < students.size(); j++) {
if (idOfStudent.equals(students.get(j).getID())) {
nameOfStudent = students.get(j).getName();
}
}
if (nameOfStudent == null) {
System.out.println(idOfStudent + " not found");
} else {
System.out.printf(answers.get(i).getID() + " " + nameOfStudent + ": ");
for (int j = 0; j < sizeOfScores; j++) {
System.out.printf("%d", scores.get(j));
if (j < sizeOfScores - 1) {
System.out.print(" ");
}
}
System.out.printf("~%d\n", sumOfScores);
}
}
/*public boolean judge(String answer, String standAnswer) {
if (answer.equals(standAnswer)) {
return true;
}
return false;
}*/
public String judge(String answer, Question question) {
if(question instanceof Single){
return Single.judge(answer,question.getStandAnswer());
}else if(question instanceof MultiChoice){
return MultiChoice.judge(answer,question.getStandAnswer());
}else if(question instanceof FillBlank){
return FillBlank.judge(answer,question.getStandAnswer());
}
return "false";
}
}
再修改问题类为抽象问题类。
类图如下:
圈复杂度如下:
题目分析:
本次题目集在前一次基础上增加了填空题与多选题的判断,输入数据的处理就更关键,从优化结构的角度出发,增添一个新的类专门处理输入信息,为了遵循迪米特法则专门增添Agent类对多个类进行联系,对于多选题则增添multiChoice类继承抽象问题类进行多选题的信息处理,填空题类则增添FillBlank类继承父类抽象问题类具体实现填空题的处理
踩坑心得:
本次题目集迭代自第三次题目集,但是第三次题目集的设计结构并不合理,起初设想设计多选题类,填空题类,单选题类,但并没有考虑到他们同属于问题类,可以通过继承实现属性的传递,故而将结构整的过于复杂且重复度极高。
且在此前并没有设计Agent中介类,好多的方法都被杂糅到不同的类之间,本次增添Agent类后结构不仅更加清晰,代码的可阅读性也得到了极大的提升,由于Agent类是中介类,于是各种的排序方法以及部分判断方法都交由他进行处理,更加具体的满足了迪米特法则的需要。
但是整体而言还是有很大的改进空间,还需要多加练习仔细打磨。
2.PTA第五次习题集
本次题目集启用了新的题目
题目如下:
智能家居是在当下家庭中越来越流行的一种配置方案,它通过物联网技术将家中的各种设备(如音视频设备、照明系统、窗帘控制、空调控制、安防系统、数字影院系统、影音服务器、影柜系统、网络家电等)连接到一起,提供家电控制、照明控制、电话远程控制、室内外遥控、防盗报警、环境监测、暖通控制、红外转发以及可编程定时控制等多种功能和手段。与普通家居相比,智能家居不仅具有传统的居住功能,兼备建筑、网络通信、信息家电、设备自动化,提供全方位的信息交互功能。请根据如下要去设计一个智能家居强电电路模拟系统。
1、控制设备模拟
本题模拟的控制设备包括:开关、分档调速器、连续调速器。
开关:包括0和1两种状态。
开关有两个引脚,任意一个引脚都可以是输入引脚,而另一个则是输出引脚。开关状态为0时,无论输入电位是多少,输出引脚电位为0。当开关状态为1时,输出引脚电位等于输入电位。
分档调速器
按档位调整,常见的有3档、4档、5档调速器,档位值从0档-2(3/4)档变化。本次迭代模拟4档调速器,每个档位的输出电位分别为0、0.3、0.6、0.9倍的输入电压。
连续调速器
没有固定档位,按位置比例得到档位参数,数值范围在[0.00-1.00]之间,含两位小数。输出电位为档位参数乘以输入电压。
所有调速器都有两个引脚,一个固定的输入(引脚编号为1)、一个输出引脚(引脚编号为2)。当输入电位为0时,输出引脚输出的电位固定为0,不受各类开关调节的影响。
所有控制设备的初始状态/档位为0。
控制设备的输入引脚编号为1,输出引脚编号为2。
2、受控设备模拟
本题模拟的受控设备包括:灯、风扇。两种设备都有两根引脚,通过两根引脚电压的电压差驱动设备工作。
灯有两种工作状态:亮、灭。在亮的状态下,有的灯会因引脚电位差的不同亮度会有区别。
风扇在接电后有两种工作状态:停止、转动。风扇的转速会因引脚的电位差的不同而有区别。
本次迭代模拟两种灯具。
白炽灯:
亮度在0~200lux(流明)之间。
电位差为0-9V时亮度为0,其他电位差按比例,电位差10V对应50ux,220V对应200lux,其他电位差与对应亮度值成正比。白炽灯超过220V。
日光灯:
亮度为180lux。
只有两种状态,电位差为0时,亮度为0,电位差不为0,亮度为180。
本次迭代模拟一种吊扇。
工作电压区间为80V-150V,对应转速区间为80-360转/分钟。80V对应转速为80转/分钟,150V对应转速为360转/分钟,超过150V转速为360转/分钟(本次迭代暂不考虑电压超标的异常情况)。其他电压值与转速成正比,输入输出电位差小于80V时转速为0。
输入信息:
1、设备信息
分别用设备标识符K、F、L、B、R、D分别表示开关、分档调速器、连续调速器、白炽灯、日光灯、吊扇。
设备标识用标识符+编号表示,如K1、F3、L2等。
引脚格式:设备标识-引脚编号,例如:K1-1标识编号为1的开关的输入引脚。
三种控制开关的输入引脚编号为1,输出引脚编号为2。
受控设备的两个引脚编号分别为1、2。
约束条件:
不同设备的编号可以相同。
同种设备的编号可以不连续。
设备信息不单独输入,包含在连接信息中。
2、连接信息
一条连接信息占一行,用[]表示一组连接在一起的设备引脚,引脚与引脚之间用英文空格" "分隔。
格式:"["+引脚号+" "+...+" "+引脚号+"]"
例如:[K1-1 K3-2 D5-1]表示K1的输入引脚,K3的输出引脚,D5的1号引脚连接在一起。
约束条件:
本次迭代不考虑两个输出引脚短接的情况
考虑调速器输出串联到其他控制设备(开关)的情况
不考虑调速器串联到其他调速器的情况。
不考虑各类控制设备的并联接入或反馈接入。例如,K1的输出接到L2的输入,L2的输出再接其他设备属于串联接线。K1的输出接到L2的输出,同时K1的输入接到L2的输入,这种情况属于并联。K1的输出接到L2的输入,K1的输入接到L2的输出,属于反馈接线。
3、控制设备调节信息
开关调节信息格式:
#+设备标识K+设备编号,例如:#K2,代表切换K2开关的状态。
分档调速器的调节信息格式:
#+设备标识F+设备编号+"+" 代表加一档,例如:#F3+,代表F3输出加一档。
#+设备标识F+设备编号+"-" 代表减一档,例如:#F1-,代表F1输出减一档。
连续调速器的调节信息格式:
#+设备标识L+设备编号+":" +数值
代表将连续调速器的档位设置到对应数值,例如:#L3:0.6,代表L3输出档位参数0.6。
4、电源接地标识:VCC,电压220V,GND,电压0V。没有接线的引脚默认接地,电压为0V。
输入信息以end为结束标志,忽略end之后的输入信息。
输出信息:
按开关、分档调速器、连续调速器、白炽灯、日光灯、吊扇的顺序依次输出所有设备的状态或参数。每个设备一行。同类设备按编号顺序从小到大输出。
输出格式:@设备标识+设备编号+":" +设备参数值(控制开关的档位或状态、灯的亮度、风扇的转速,只输出值,不输出单位)
连续调速器的档位信息保留两位小数,即使小数为0,依然显示两位小数.00。
开关状态为0(打开)时显示turned on,状态为1(合上)时显示closed
如:
@K1:turned on
@B1:190
@L1:0.60
本题不考虑输入电压或电压差超过220V的情况。
本题只考虑串联的形式,所以所有测试用例的所有连接信息都只包含两个引脚
本题电路中除了开关可能出现多个,其他电路设备均只出现一次。
电源VCC一定是第一个连接的第一项,接地GND一定是最后一个连接的后一项。
我的部分代码如下:
class DataDeal {
private ArrayList<String> lines;
private ArrayList<String> devices;
private ArrayList<String> operations;
public DataDeal() {
}
public DataDeal(ArrayList<String> lines) {
this.lines = lines;
this.devices = new ArrayList<>();
this.operations = new ArrayList<>();
common();
}
public ArrayList<String> getLines() {
return lines;
}
public void setLines(ArrayList<String> lines) {
this.lines = lines;
}
public ArrayList<String> getDevices() {
return devices;
}
public void setDevices(String load) {
this.devices.add(load);
}
public ArrayList<String> getOperations() {
return operations;
}
public void setOperations(String operation) {
this.operations.add(operation);
}
public void common() {
for (int i = 0; i < lines.size(); i++) {
if (lines.get(i).contains("[")) {
devices.add(lines.get(i));
} else if (lines.get(i).contains("#")) {
operations.add(lines.get(i));
}
}
}
public ArrayList<String> dealNames() {
ArrayList<String> names = new ArrayList<>();
for (int i = 0; i < devices.size(); i++) {
String regex = "[A-Z]\\d";
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(devices.get(i));
while (matcher.find()) {
names.add(matcher.group());
}
}
Set<String> set = new LinkedHashSet<>(names);
names.clear();
names.addAll(set);//去除里面重复的名字
return names;
}
public ArrayList<Integer> dealPins() {
ArrayList<String> oldPins = new ArrayList<>();
for (int i = 0; i < devices.size(); i++) {
String regex = "-\\d";
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(devices.get(i));
while (matcher.find()) {
oldPins.add(matcher.group());
}
}
ArrayList<Integer> pins = new ArrayList<>();
for (int i = 0; i < oldPins.size(); i++) {
String regex = "\\d";
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(oldPins.get(i));
while (matcher.find()) {
pins.add(Integer.parseInt(matcher.group()));
}
}
return pins;
}
public ArrayList<String> dealOperations() {
ArrayList<String> names = new ArrayList<>();
for (int i = 0; i < operations.size(); i++) {
String regex = "[A-Z]\\d";
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(operations.get(i));
while (matcher.find()) {
names.add(matcher.group());
}
}
return names;
}
}
负载电器类:
class ElectricLoad {
protected int fontPin;
protected int backPin;
protected double inputVoltage;
protected double outputVoltage;
protected String name;
protected int num;
protected double state;
protected double voltage;
public ElectricLoad() {
}
public ElectricLoad(int fontPin, int backPin, String name) {
this.fontPin = fontPin;
this.backPin = backPin;
this.name = name;
this.num = isNum();
}
public int isNum() {
String str = "";
for (int i = 0; i < name.length(); i++) {
if (name.charAt(i) >= 48 && name.charAt(i) <= 57) {
str += name.charAt(i);
}
}
return Integer.parseInt(str);
}
public int getFontPin() {
return fontPin;
}
public void setFontPin(int fontPin) {
this.fontPin = fontPin;
}
public int getBackPin() {
return backPin;
}
public void setBackPin(int backPin) {
this.backPin = backPin;
}
public double getInputVoltage() {
return inputVoltage;
}
public void setInputVoltage(double inputVoltage) {
this.inputVoltage = inputVoltage;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getNum() {
return num;
}
public void setNum(int num) {
this.num = num;
}
public double getOutputVoltage() {
return outputVoltage;
}
public void setOutputVoltage(double outputVoltage) {
this.outputVoltage = outputVoltage;
}
public double getState() {
return state;
}
public void setState(double state) {
this.state = state;
}
public double getVoltage() {
return voltage;
}
public void setVoltage(double voltage) {
this.voltage = voltage;
}
}
抽象控制类:
abstract class Control extends ElectricLoad {
public Control() {
}
public Control(int fontPin, int backPin, String name) {
super(fontPin, backPin, name);
}
abstract public void changeState(String str);
abstract public double loadVoltage();
}
分段调节器类:
class FenGovernor extends Control {//分段调节
public FenGovernor() {
}
public FenGovernor(int fontPin, int backPin, String name) {
super(fontPin, backPin, name);
this.state = 0;
}
@Override
public void changeState(String str) {
if (str.equals("+") && state <= 2) {
state++;
} else if (str.equals("-") && state >= 1) {
state--;
}
}
@Override
public double loadVoltage() {
if (state == 0) {
return 0;
} else if (state == 1) {
return 0.3;
} else if (state == 2) {
return 0.6;
} else if (state == 3) {
return 0.9;
}
return 0;
}
}
连续调节类:
class ContGovernor extends Control {//连续调节
public ContGovernor() {
}
public ContGovernor(int fontPin, int backPin, String name) {
super(fontPin, backPin, name);
state = 0;
}
@Override
public void changeState(String str) {
setState(Double.parseDouble(str));
}
@Override
public double loadVoltage() {
return state;
}
}
被控电器类:
abstract class BeControl extends ElectricLoad {
public BeControl() {
}
public BeControl(int fontPin, int backPin, String name) {
super(fontPin, backPin, name);
}
abstract public void stateOfControl();
}
具体的电器类:
class IncandescentLamp extends BeControl {//白炽灯
public IncandescentLamp() {
}
public IncandescentLamp(int fontPin, int backPin, String name) {
super(fontPin, backPin, name);
this.state = 0;
}
@Override
public void stateOfControl() {
if (voltage <= 9) {
state = 0;
} else if (voltage > 9) {
state = (5.0 / 7.0) * voltage + (300.0 / 7.0);
}
}
}
其他中介类(Agent)和View类都是对信息进行处理,其他具体电器类也是与上面所示电器类有较多重复之处,此处不做展示。
类图如下:
圈复杂度如下:
题目分析:
本次题目更换后,难度相较之前有明显的降低,难度降低后问题的结构更加清晰简单了,思路与前四次题目集并无二致,先构造父类,在分别由子类继承并实现各自的功能,如本题中控制类则对应分段控制与连续控制,受控设备则包含白炽灯,电扇等。对于电路连接的问题则专门设计一个检查类进行检查,最终将诸多处理数据的方法交由agent类进行整合处理。
踩坑心得:
本次实验由于是第一次实验不考虑电路连接的诸多情况,故而在受控设备输入输出端的要求不高,难度自然也就不是很高,但是在书写过程中也还是遇到一些问题,无法确定设备连接情况,为此专门在调试环节加入输出连接情况,反复调试后顺利解决这一问题,
3.PTA第六次习题集
基于第五次习题集,本次习题做出一些迭代如下:
前面的题目要求都有在上文第五次习题集中提及,故而本处不再复述
本次迭代模拟一种落地扇。
工作电压区间为 [80V,150V],对应转速区间为 80-360 转/分钟。电压在[80,100)V 区间对应转速为 80 转/分 钟,[100-120)V 区间对应转速为 160 转/分钟,[120-140)V 区间对应转速为 260 转/分钟,超过 140V 转速 为 360 转/分钟(本次迭代暂不考虑电压超标的异常情况)输入信息:
本次迭代考虑电阻:白炽灯的电阻为 10,日光灯的电阻为 5,吊扇的电阻为 20,落 地扇的电阻为 20
3、输入信息
1)输入设备信息
分别用设备标识符K、F、L、B、R、D、A分别表示开关、分档调速器、连续调速器、白炽灯、日光灯、吊扇、落地扇。
设备标识用标识符+编号表示,如K1、F3、L2等。
引脚格式:设备标识-引脚编号,例如:K1-1标识编号为1的开关的输入引脚。
三种控制开关的输入引脚编号为1,输出引脚编号为2。
受控设备的两个引脚编号分别为1、2。
约束条件:
不同设备的编号可以相同。
同种设备的编号可以不连续。
设备信息不单独输入,包含在连接信息中。
2)输入连接信息
一条连接信息占一行,用[]表示一组连接在一起的设备引脚,引脚与引脚之间用英文空格" "分隔。
格式:"["+引脚号+" "+...+" "+引脚号+"]"
例如:[K1-1 K3-2 D5-1]表示K1的输入引脚,K3的输出引脚,D5的1号引脚连接在一起。
约束条件:
不考虑调速器串联到其他调速器的情况。
不考虑调速器串联到其他调速器的情况。
考虑各类设备的并联接入。例如,K1 的输出接到 L2 的输入,L2 的输出再接其他设备属于串联接线。K1 的输出接到 L2 的输出,同时 K1 的输入接到 L2 的输入,这种情况属于并联。
本次迭代的连接信息不单独输入,包含在线路信息中。
3)输入控制设备调节信息
开关调节信息格式:
#+设备标识K+设备编号,例如:#K2,代表切换K2开关的状态。
分档调速器的调节信息格式:
#+设备标识F+设备编号+"+" 代表加一档,例如:#F3+,代表F3输出加一档。
#+设备标识F+设备编号+"-" 代表减一档,例如:#F1-,代表F1输出减一档。
连续调速器的调节信息格式:
#+设备标识L+设备编号+":" +数值 代表将连续调速器的档位设置到对应数值,例如:#L3:0.6,代表L3输出档位参数0.6。
4)电源接地标识:
VCC,电压220V,GND,电压0V。没有接线的引脚默认接地,电压为0V。
5)输入串联电路信息
一条串联电路占一行,串联电路由按从靠电源端到接地端顺序依次输入的 n 个连接 信息组成,连接信息之间用英文空格" "分隔。
串联电路信息格式:
"#T"+电路编号+":"+连接信息+" "+连接信息+...+" "+连接信息
例如:#T1:[IN K1-1] [K1-2 D2-1] [D2-2 OUT] 一个串联电路的第一个引脚是 IN,代表起始端,靠电源。最后一个引脚是 OUT,代表结尾端, 靠接地。
约束条件:
不同的串联电路信息编号不同。
输入的最后一条电路信息必定是总电路信息,总电路信息的起始引脚是 VCC,结束引脚是 GND。
连接信息中的引脚可能是一条串联或并联电路的 IN 或者 OUT。例如:
#T1:[IN K1-1] [K1-2 T2-IN] [T2-OUT OUT]
#T1:[IN K1-1] [K1-2 T2-IN] [T2-OUT M2-IN] [M2-OUT OUT]
6)输入并联电路信息
一条并联电路占一行,并联电路由其包含的几条串联电路组成,串联电路标识之间用英文空格" "分隔。
格式:
"#M"+电路编号+":"+”[”+串联电路信息+" "+....+" "+串联电路信息+”]”
例如:#M1:[T1 T2 T3]
该例声明了一个并联电路,由 T1、T2、T3 三条串联电路并联而成,三条串联电路的 IN 短 接在一起构成 M1 的 IN,三条串联电路的 OUT 短接在一起构成 M1 的 OUT。
约束条件:
本次迭代不考虑并联电路中包含并联电路的情况,也不考虑多个并联电路串联的情况。
调速器的输入端只会直连VCC,不会接其他设备。整个电路最多只有连接在电源上的一个调速器,且不包含在并联单路中。
我的部分代码如下:
并联类:
class BingM extends ElectricLoad{
private ArrayList<ChuanT> chuanTS = new ArrayList<>();
public BingM(){}
public BingM(String name,ArrayList<ChuanT> chuanTS){
this.chuanTS = chuanTS;
this.name = name;
}
public ArrayList<ChuanT> getChuanTS() {
return chuanTS;
}
public void setChuanTS(ArrayList<ChuanT> chuanTS) {
this.chuanTS = chuanTS;
}
}
串联类:
class ChuanT {
private int num;
private ArrayList
private boolean state = false;
private double resistance = 0;
public ChuanT() {}
public ChuanT(int num,ArrayList<ElectricLoad> devices) {
this.num = num;
this.devices = devices;
}
public int getNum() {
return num;
}
public void setNum(int num) {
this.num = num;
}
public ArrayList<ElectricLoad> getDevices() {
return devices;
}
public void setDevices(ArrayList<ElectricLoad> devices) {
this.devices = devices;
}
public boolean isState() {
return state;
}
public void setState(boolean state) {
this.state = state;
}
public double getResistance() {
return resistance;
}
public void setResistance(double resistance) {
this.resistance = resistance;
}
}
修改受控父类为装置父类以实现他的多个具体电器子类:
abstract class Devices extends ElectricLoad {
public Devices() {
}
public Devices(int fontPin, int backPin, String name) {
super(fontPin, backPin, name);
}
abstract public void stateOfControl();
}
由于其他子类在前文有所展示故此处不再重新展示,只展示新增的落地扇类
class LuoDiFan extends Devices {
public LuoDiFan(){}
public LuoDiFan(int fontPin, int backPin, String name) {
super(fontPin, backPin, name);
this.state = 0;
setResistance(20);
}
@Override
public void stateOfControl() {
if (voltage < 80) {
state = 0;
} else if (voltage >= 80 && voltage <= 99) {
state = 80;
} else if (voltage >= 100 && voltage <=119) {
state = 160;
}else if(voltage >= 120 && voltage <= 139){
state = 260;
}else if(voltage > 140){
state = 360;
}
}
}
Main类则简简单单负责输入并传递输入数据即可
public class Main {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
ArrayList<String> lines = new ArrayList<>();
while (true) {
String str = input.nextLine();
if (str.equals("end")) {
break;
}
lines.add(str);
}
DataDeal dataDeal = new DataDeal(lines);
Series series = new Series();
Agent agent = new Agent(series, dataDeal);
agent.initialize();
View view = new View(agent);
view.display();
}
}
类图如下:
上半部分类图:
下半部分类图:
圈复杂度如下:
题目分析:
本题要求增添并联线路,添加并联线路后对之前设计的整个结构都有一些动摇,说明在第五次实验中所做的设计仍然存在不合理的地方,并联线路就需要很仔细的考虑到设备接线柱的问题了,既要做到连接又要确保满足并联条件的输入与输出,难度相较于第五次题目集可以说有了质的飞跃
踩坑心得:
处理并联问题真的是很棘手,搞了好久也还是模棱两可,这个地方的处理还是想不到什么方法去解决,对所有的类的设计进行了大的调整,结构发生一些改变,最大的启示应该是始终牢记开闭原则,在设计类图时要考虑清楚可能会增添哪些部分的功能,以便于后续迭代时的功能增加。
三.改进建议
1.经过这三次的题目集练习,已经初步掌握了通过继承,抽象的方法实现诸多的功能,例如子类继承父类来实现属性的传递,避免了重复定义产生垃圾代码
2.正则表达式还是很难记得住,但是通过多次的练习已经开始熟悉起来了
3.比起敲代码,设计整个系统的类图才是更难的一步,更加优秀的设计思想还需要多多吸纳学习
四.总结
经过这一个周目的学习,有明确的看到随着迭代题目难度的上升,也深刻的感受到个人能力的不足,例如第四次题目集和第六次题目集都让我寸步难行,看到别的同学进行迭代,而自己的作业需要大篇幅的重写,不禁认识到问题的严重性,还需要多多查阅网络资料翻阅书本,更多的接触优秀的设计思路,优秀的设计之下代码的实现并非难事。这三周的三次作业的完成情况不佳,自我分析应当是投入的时间还不够,日后还需倾注更多的精力才能把java作业完成好,
标签:String,get,--,ArrayList,blog2,PTA,引脚,int,public From: https://www.cnblogs.com/Bofeng-Blogs/p/18229878