第二輪下來最大的體會是自己的程式碼相較之前精煉了很多,從第四次作業開始注重了遵循單一職責原則。在做需求分析這方面也花了更多心思以更好地面對之後的迭代。
關於OOP中的單一職責:
前一輪大作業我把用到的方法全部堆在了主函式里,一個主函式能有四五百行。這次學會了用“代理者”Agent,主函式只負責輸入和輸出,程式碼可讀性大大增加了。做題前要確認好類間關係以及各種屬性應該安排在哪個類中。
三次作業的bug分析:
第四次大作業:
1.沒有設定一個學生類,導致多個學生作答的情況的測試點只過一兩個;(果然還是需求分析這方面沒做好= =)
2.多人多試卷亂序輸入時邏輯過於混亂導致輸出也是完全錯的
3.刪除已經儲存的資訊後會出錯(沒有用List類而用的普通的陣列)
第五次大作業:
1.最初沒考慮檔位上下限,做出了一個能無限升檔和降檔的調速器= =
第六次大作業:
1.輸出的某個資料的格式不符合要求(但是結果提示的是答案錯誤不是格式錯誤害得我改了三個多小時沒發現是格式錯誤555)
2.最初的需求分析沒做好,沒有做到普遍性
對bug的總結:
1.在做需求分析的時候一定要全面考慮,要追求普遍情況而非特殊情況,比如第四次作業潛意識認為只有一個學生,多個學生的情況完全沒有辦法。
2.不能疏忽題目要求,在程式碼沒有邏輯錯誤和算術錯誤的情況下最應該先檢查資料輸出格式。
3.每一個類有什麼限制都要了解清楚,不然真的貽笑大方了(我那檔位爆炸的調速器)
下面是每次大作業的具體分析:
第四次大作業:
第四次大作業仍然是答題判題程式,透過增加題目種類(多選題,單選題,填空題)以考察繼承與多型的學習成果。
SourceMonitor給到的程式碼分析:
從程式碼行數也能看出MatcherAndSeparation是比較關鍵的類,起到了一個代理的作用,最主要的邏輯也是寫在其中。
類圖:
踩坑心得
在寫完多選題類後跑程式發現得到的答案都是正確的,但是一分沒拿到,改了很久才發現是題目輸入樣例自帶了個空格在答案後面,輸出時我把那個空格一併輸出了導致格式錯誤。很多時候在答案正確情況下最應該先檢查格式問題。
改進建議
程式裡同時存在一個抽象類Question和一個Question應該是當時我想把儲存好的三種題型再總和到一起,但類圖顯示抽象類Question和Question兩者之間沒有聯絡,現在想想做成繼承關係的話也能省不少程式碼了= =
第五、六次大作業:
第五次比較簡單,就和迭代後的第六次放一起分析了
第六次大作業的程式碼分析:
主要方法放在了Agent函式里,寫了四百多行,已經是最佳化了一遍後的行數了,問了下身邊同學的總行數和我差不多,都是九百多行。
類圖:
在第五次作業的串聯電路基礎上增加了並聯電路的實現。
踩坑心得:
一開始思維沒有開啟,下意識認為題目就是侷限在只有兩條支路的並聯電路,於是寫的情況也是針對只有兩條支路的情況,寫的程式碼行數很多拿到的分卻很少。後來全部重寫了一遍,做成普遍情況後有n條電路都沒問題。
總體還是偏簡單的,但我卡殼了幾個小時,最後是找了好幾個大佬互測了一下才發現自己是資料格式輸出錯誤,編譯器寫的是正確的格式,pta上的是錯誤的版本,導致我把其他人給的樣例過了一遍發現計算結果都沒問題還是沒拿到分。
改正後36個測試點還有6個沒過,但和其他人交流時發現即使是滿分程式碼也有bug,比如斷路情況下電路中的電器仍然能工作,所以這幾個測試點一時半會真不知道到底是什麼問題。
改進建議:
Agent函式里重複的程式碼太多了,幾乎全是同樣的for迴圈,如果把重複的地方單獨做成一個方法類的話能讓程式碼精簡很多。
二輪下來的總結
最大的缺點是程式碼中仍舊出現了很多的if語句和for迴圈(說人話其實就是垃圾程式碼),諸如此類:
if (arr.startsWith("#N:")) {
if(arr.matches("#N:[0-9]+[ ]#Q:.+[ ]#A:.*")){
String[] a = arr.split(" * #A: *| * #Q:*|#N:");
if(a.length == 3){
single[Integer.parseInt(a[1])] = new SingleKind(Integer.parseInt(a[1]), a[2].trim(), "","s");
}
else {
String answer = a[3].replaceAll("\\s+$","");
single[Integer.parseInt(a[1])] = new SingleKind(Integer.parseInt(a[1]), a[2].trim(), answer.trim(),"s");
}
}else {
System.out.println("wrong format:" + arr);
}
}
else if (arr.startsWith("#K:")) {
if(arr.matches("#K:[0-9]+[ ]#Q:.+[ ]#A:.*")){
String[] a = arr.split(" * #A: *| * #Q:*|#K:");
if(a.length == 3){
fillblank[Integer.parseInt(a[1])] = new FillblankKind(Integer.parseInt(a[1]), a[2].trim(), "","f");
}
else {
String answer = a[3].replaceAll("\\s+$","");
fillblank[Integer.parseInt(a[1])] = new FillblankKind(Integer.parseInt(a[1]), a[2].trim(), answer.trim(),"f");
}
}else {
System.out.println("wrong format:" + arr);
}
}
else if (arr.startsWith("#Z:")) {
if(arr.matches("#Z:[0-9]+[ ]#Q:.+[ ]#A:.*")){
String[] a = arr.split(" * #A: *| * #Q:*|#Z:");
if(a.length == 3){
multiple[Integer.parseInt(a[1])] = new MultipleKind(Integer.parseInt(a[1]), a[2].trim(), "","m");
}
else {
String answer = a[3].replaceAll("\\s+$","");
multiple[Integer.parseInt(a[1])] = new MultipleKind(Integer.parseInt(a[1]), a[2].trim(), answer,"m");
}
}else {
System.out.println("wrong format:" + arr);
}
}
else if (arr.startsWith("#T:")) {
if(arr.matches("#T:[0-9]+([ ][0-9]+[-][0-9]+)*")){
t++;
int g = 1;
String[] a = arr.split("\\s+|-+|#T:");
paper[Integer.parseInt(a[1])] = new TestPaper(Integer.parseInt(a[1]), (a.length - 2) / 2);
for (int j = 0; j < a.length - 2; j += 2) {
paper[(Integer.parseInt(a[1]))].setStandardGrade(g, Integer.parseInt(a[3 + j]));
g++;
}
for (int j = 1, m = 2; j <= (a.length - 2) / 2; j += 1, m += 2) {
paper[(Integer.parseInt(a[1]))].saveQuestionNum( j, Integer.parseInt(a[m]));
}
}
else {
System.out.println("wrong format:" + arr);
}
}
else if (arr.startsWith("#S:")) {
if(arr.matches("#S:\\d+ \\d+( #A:\\d+-.*)*")){
ans++;
int num = 0;
String[] a = arr.split(" *#S:*| *#A:*|[-]+");
if(a.length % 2 == 0) {
String[] a2 = a[1].split(" ");
this.answer[ans] = new AnswerPaper(Integer.parseInt(a2[0]), a2[1], (a.length - 2) / 2);
for (int i = 1, j = 3; j <= a.length; i++, j += 2) {
if(Character.isWhitespace(a[j].charAt(a[j].length()-1))) {
answer[ans].setStudentAnswer(i, a[j].substring(0, a[j].length() - 1));
}
else {
answer[ans].setStudentAnswer(i, a[j]);
}
}
}else{
String[] a2 = a[1].split(" ");
this.answer[ans]=new AnswerPaper(Integer.parseInt(a2[0]), a2[1], (a.length - 1) / 2);
for (int i = 1, j = 3; j <= a.length - 2; i++, j += 2) {
if(Character.isWhitespace(a[j].charAt(a[j].length()-1))) {
answer[ans].setStudentAnswer(i, a[j].substring(0, a[j].length() - 1));
}
else {
answer[ans].setStudentAnswer(i, a[j]);
}
num = i;
}
num += 1;
answer[ans].setStudentAnswer(num, "");
}
for (int i = 1, j = 2; j < a.length; i++, j+=2) {
answer[ans].setStudentQuestion(i, Integer.parseInt(a[j]));
}
}else {
System.out.println("wrong format:" + arr);
}
}
else if (arr.startsWith("#X:")) {
if(arr.matches("#X:[0-9]+([ ]\\w+[-][0-9]+)*[ ]\\w+")){
String[] a = arr.split("\\s+|-+|#X:");
for (int j = 1, m = 2; j <= (a.length - 1) / 2+1; j += 2, m += 2) {
this.students.put(a[j], a[m]);
stu++;
}
}else {
System.out.println("wrong format:" + arr);
}
}
else if (arr.startsWith("#D:N-")) {
if(arr.matches("#D:N-[0-9]+")){
String[] a = arr.split("#D:N-");
int questionNum = Integer.parseInt(a[1]);
this.deletedQuestions.add(questionNum);
single[questionNum] = new SingleKind(questionNum, null, null,"s");
multiple[questionNum] = new MultipleKind(questionNum, null, null,"m");
fillblank[questionNum] = new FillblankKind(questionNum, null, null,"f");
}else {
System.out.println("wrong format:" + arr);
}
}
else {
System.out.println("wrong format:" + arr);
}
int k=1;
for(k=1;k<100;k++) {
if(single[k]!=null) {
question[k]=new Question(single[k].getQuestionNum(),single[k].getQuestionContent(),single[k].getStandAnswer(),"s");
}
if(multiple[k]!=null) {
question[k]=new Question(multiple[k].getQuestionNum(),multiple[k].getQuestionContent(),multiple[k].getStandAnswer(),"m");
}
if(fillblank[k]!=null) {
question[k]=new Question(fillblank[k].getQuestionNum(),fillblank[k].getQuestionContent(),fillblank[k].getStandAnswer(),"f");
}
}
}
缺點
學到的各種模式沒使用過,為了在一週時間內邊上課邊寫大作業於是只敢在“舒適圈”中用些自己比較習慣的寫法,希望自己在之後空閒下來的時間去鑽研和掌握課上學到的模式。
進步
在分析類間關係上更熟練了,繼承和多型的使用和遵循了單一職責也使得未來迭代後不需要花太多時間去修改。在這方面也有實驗的功勞,我在實驗上花了不少心思後對做需求分析和設計類間關係上更加有方向了。還有就是對List類有了更多的瞭解,用起來很方便,之前一直用普通陣列解決問題導致幾乎無法增刪情況。
未來展望:
多啃啃Java課本,學會更多方法有助於最佳化程式碼,和身邊同學交流一下看看他們用的哪些好用迅速的方法還是很有必要的。要敢於去溝通交流互測程式碼才能及時發現自己的錯誤。要多多享受這種查缺補漏的過程。在大作業適當降低難度後我也能更快完成作業,空閒的時間也多了出來,對OOP的熱情也是保持了。