blog2 4--6周PTA训练总结

一.前言

经过了第二轮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=5true

4+6=22false.

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 lines = new ArrayList<>();
private ArrayList lineN = new ArrayList<>();
private ArrayList lineT = new ArrayList<>();
private ArrayList lineS = new ArrayList<>();
private String lineX;
private String lineD;

public InputDeal() {
}

public InputDeal(ArrayList lines) {
this.lines = lines;
}

public String getLineD() {
return lineD;
}

public String getLineX() {
return lineX;
}

public ArrayList NDeal() {
ArrayList 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 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 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 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 TDeal() {
ArrayList 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 nunOfQuestions = new ArrayList<>();
ArrayList 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 SDeal() {
ArrayList 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 nunOfTests = new ArrayList<>();
ArrayList answersOfQuestions = new ArrayList<>();
ArrayList 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 XDeal() {

ArrayList 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 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 questions;
private ArrayList tests;
private ArrayList answers;
private ArrayList students;
private Delete delete;
private InputDeal inputDeal;

public Agent() {
}

public Agent(ArrayList questions, ArrayList tests, ArrayList answers, ArrayList students, InputDeal inputDeal) {
this.questions = questions;
this.tests = tests;
this.students = students;
this.answers = answers;
this.inputDeal = inputDeal;
}

public ArrayList getQuestions() {
return questions;
}

public void setQuestions(ArrayList questions) {
this.questions = questions;
}

public ArrayList getTests() {
return tests;
}

public void setTests(ArrayList tests) {
this.tests = tests;
}

public ArrayList getAnswers() {
return answers;
}

public void setAnswers(ArrayList answers) {
this.answers = answers;
}

public ArrayList getStudents() {
return students;
}

public void setStudents(ArrayList 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 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 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 lines;
private ArrayList devices;
private ArrayList operations;

public DataDeal() {
}

public DataDeal(ArrayList lines) {
this.lines = lines;
this.devices = new ArrayList<>();
this.operations = new ArrayList<>();
common();
}

public ArrayList getLines() {
return lines;
}

public void setLines(ArrayList lines) {
this.lines = lines;
}

public ArrayList getDevices() {
return devices;
}

public void setDevices(String load) {
this.devices.add(load);
}

public ArrayList 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 dealNames() {

ArrayList 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 set = new LinkedHashSet<>(names);
names.clear();
names.addAll(set);//去除里面重复的名字

return names;
}

public ArrayList dealPins() {
ArrayList 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 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 dealOperations() {
ArrayList 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 chuanTS = new ArrayList<>();
public BingM(){}
public BingM(String name,ArrayList chuanTS){
this.chuanTS = chuanTS;
this.name = name;
}

public ArrayList getChuanTS() {
return chuanTS;
}

public void setChuanTS(ArrayList chuanTS) {
this.chuanTS = chuanTS;
}
}
串联类:
class ChuanT {
private int num;
private ArrayList devices = new ArrayList<>();
private boolean state = false;
private double resistance = 0;

public ChuanT() {}

public ChuanT(int num,ArrayList devices) {
this.num = num;
this.devices = devices;
}

public int getNum() {
return num;
}

public void setNum(int num) {
this.num = num;
}

public ArrayList getDevices() {
return devices;
}

public void setDevices(ArrayList 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 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作业完成好,

posted @ 2024-06-05 12:47  kurukuru  阅读(74)  评论(0)    收藏  举报