BLOG2

安麟之發表於2024-11-23

第四次大作業
7-3 答題判題程式-4
分數 82
困難
作者 蔡軻
單位 南昌航空大學
設計實現答題程式,模擬一個小型的測試,要求輸入題目資訊、試卷資訊、答題資訊、學生資訊、刪除題目資訊,根據輸入題目資訊中的標準答案判斷答題的結果。本題在答題判題程式-3基礎上新增的內容統一附加在輸出格式說明之後,用粗體標明。
新增內容:
1、輸入選擇題題目資訊
題目資訊為獨行輸入,一行為一道題,多道題可分多行輸入。
格式:"#Z:"+題目編號+" "+"#Q:"+題目內容+" "#A:"+標準答案
格式基本的約束與一般的題目輸入資訊一致。
新增約束:標準答案中如果包含多個正確答案(多選題),正確答案之間用英文空格分隔。
例如:

   #Z:2 #Q:宋代書法有蘇黃米蔡四家,分別是: #A:蘇軾 黃庭堅 米芾 蔡襄

多選題輸出:
輸出格式與一般答卷題目的輸出一致,判斷結果除了true、false,增加一項”partially correct”表示部分正確。
多選題給分方式:
答案包含所有正確答案且不含錯誤答案給滿分;包含一個錯誤答案或完全沒有答案給0分;包含部分正確答案且不含錯誤答案給一半分,如果一半分值為小數,按截尾規則只保留整數部分。
例如:

#N:1 #Q:1+1= #A:2
#Z:2 #Q:黨十八大報告提出要加強()建設。A 政務誠信 B 商務誠信 C社會誠信 D司法公信 #A:A B C D
#T:1 1-5 2-9
#X:20201103 Tom
#S:1 20201103 #A:1-5 #A:2-A C
end

輸出:

alert: full score of test paper1 is not 100 points
1+1=~5~false
黨十八大報告提出要加強()建設。A 政務誠信 B 商務誠信 C社會誠信 D司法公信~A C~partially correct
20201103 Tom: 0 4~4

2、輸入填空題題目資訊

題目資訊為獨行輸入,一行為一道題,多道題可分多行輸入。

格式:"#K:"+題目編號+" "+"#Q:"+題目內容+" "#A:"+標準答案
格式基本的約束與一般的題目輸入資訊一致。
例如:#K:2 #Q:古琴在古代被稱為: #A:瑤琴或七絃琴
填空題輸出:

輸出格式與一般答卷題目的輸出一致,判斷結果除了true、false,增加一項”partially correct”表示部分正確。

填空題給分方式:

答案與標準答案內容完全匹配給滿分,包含一個錯誤字元或完全沒有答案給0分,包含部分正確答案且不含錯誤字元給一半分,如果一半分值為小數,按截尾規則只保留整數部分。

例如:

#N:1 #Q:1+1= #A:2
#K:2 #Q:古琴在古代被稱為: #A:瑤琴或七絃琴
#T:1 1-5 2-10
#X:20201103 Tom
#S:1 20201103 #A:1-5 #A:2-瑤琴
end
輸出:
alert: full score of test paper1 is not 100 points
1+1=~5~false
古琴在古代被稱為:~瑤琴~partially correct
20201103 Tom: 0 5~5
 

3、輸出順序變化

只要是正確格式的資訊,可以以任意的先後順序輸入各類不同的資訊。比如試卷可以出現在題目之前,刪除題目的資訊可以出現在題目之前等。

例如:

#T:1 1-5 2-10
#N:1 #Q:1+1= #A:2
#K:2 #Q:古琴在古代被稱為: #A:瑤琴或七絃琴
#X:20201103 Tom
#S:1 20201103 #A:1-5 #A:2-古箏
end
輸出:
alert: full score of test paper1 is not 100 points
1+1=~5~false
古琴在古代被稱為:~古箏~false
20201103 Tom: 0 0~0

4、多張試卷資訊
本題考慮多個同學有多張不同試卷的答卷的情況。輸出順序優先順序為學號、試卷號,按從小到大的順序先按學號排序,再按試卷號。
例如:

#T:1 1-5 2-10
#T:2 1-8 2-21
#N:1 #Q:1+1= #A:2
#S:2 20201103 #A:1-2 #A:2-古箏
#S:1 20201103 #A:1-5 #A:2-瑤琴或七絃琴
#S:1 20201104 #A:1-2 #A:2-瑟
#S:2 20201104 #A:1-5 #A:2-七絃琴
#X:20201103 Tom-20201104 Jack
#K:2 #Q:古琴在古代被稱為: #A:瑤琴或七絃琴
end
輸出:
alert: full score of test paper1 is not 100 points
alert: full score of test paper2 is not 100 points
1+1=~5~false
古琴在古代被稱為:~瑤琴或七絃琴~true
20201103 Tom: 0 10~10
1+1=~2~true
古琴在古代被稱為:~古箏~false
20201103 Tom: 8 0~8
1+1=~2~true
古琴在古代被稱為:~瑟~false
20201104 Jack: 5 0~5
1+1=~5~false
古琴在古代被稱為:~七絃琴~partially correct

本次題目分析如下:
這個題目要求設計一個複雜的答題判題程式,能夠處理多種輸入資訊,並根據這些資訊進行判題和輸出結果。程式需要考慮多種異常情況,如題目刪除、題目引用錯誤、格式錯誤等,並根據不同的題目型別(選擇題、填空題)進行不同的判分邏輯。
QuestionSet類

類名:QuestionSet
方法:
getNumber():返回問題的編號。
getContent():返回問題的內容。
getAnswerKey():返回問題的答案關鍵資訊。
isDeleted():判斷問題是否已被刪除。
setDeleted(boolean deleted):設定問題的刪除狀態。

QuestionBank

類名:QuestionBank
方法:
addQuestion(String input):根據特定格式的輸入新增普通問題到問題庫。
addChoiceQuestion(String input):根據特定格式的輸入新增選擇題到問題庫。
addFillInBlankQuestion(String input):根據特定格式的輸入新增填空題到問題庫。
getQuestionByNumber(int number):根據問題編號獲取對應的QuestionSet物件。

QuestionScore類

類名:QuestionScore
方法:
getNumber():返回問題的編號。
getScore():返回問題的分值。

TestPaper類

類名:TestPaper
方法:
setData(String input):根據特定格式的輸入設定試卷的相關資料,如編號和各題分值。
getNumber():返回試卷的編號。
getQuestionScores():返回試卷中各題分值的列表。

Student類

類名:Student
方法:
getId():返回學生的學號。
getName():返回學生的姓名。

TestPapersCollection類

類名:TestPapersCollection
方法:
addTestPaper(String input):根據特定格式的輸入新增試卷到試卷集合。
getPapers():返回試卷集合中的所有試卷列表。
getTestPaperByNumber(int number):根據試卷編號獲取對應的TestPaper物件。

AnswerSheet類

類名:AnswerSheet
方法:
setData(String input):根據特定格式的輸入設定答題卡的相關資料,如試卷編號、學生學號和答案。
getPaperNumber():返回答題卡對應的試卷編號。
getStudentId():返回答題卡對應的學生學號。
getAnswers():返回答題卡上的答案列表。

AnswerSheetsCollection類

類名:AnswerSheetsCollection
方法:
addAnswerSheet(String input):根據特定格式的輸入新增答題卡到答題卡集合。
getSheets():返回答題卡集合中的所有答題卡列表。

Evaluation類

類名:Evaluation
方法:
processAnswerSheets(QuestionBank questionBank, TestPapersCollection testPapers, AnswerSheetsCollection answerSheets, Map<String, Student> studentMap):處理答題卡集合,根據問題庫、試卷集合和學生資訊進行評分,並輸出相關結果。

我覺得本題主要的難點就在於設計功能是對學生的答題情況進行評估和計分,並輸出每個學生的成績報告。這個類它接收QuestionBank、TestPapersCollection、AnswerSheetsCollection以及Map<String, Student>作為引數,透過遍歷試卷、答題紙以及對應的問題和答案,根據設定的答案規則和分值來計算每個學生的得分,並展示詳細的成績資訊。
以下是我的具體設計:

  1. 檢查試卷總分是否為 100
點選檢視程式碼
for (TestPaper paper : testPapers.getPapers()) {
    int totalScore = paper.getQuestionScores().stream().mapToInt(QuestionScore::getScore).sum();
    if (totalScore!= 100) {
        System.out.println("alert: full score of test paper" + paper.getNumber() + " is not 100 points");
    }
}
遍歷TestPapersCollection中的每一份試卷。
透過stream和mapToInt操作對試卷中的每個QuestionScore物件獲取分數並求和,得到該試卷的總分。
如果總分不等於 100,輸出相應的警告資訊,提示試卷總分不符合預期。
2.對答題紙進行排序
點選檢視程式碼
answerSheets.getSheets().sort(Comparator.comparing(AnswerSheet::getStudentId).thenComparing(AnswerSheet::getCountryNumber));
獲取AnswerSheetsCollection中的所有答題紙列表。
使用Comparator按照學生 ID 進行排序,如果學生 ID 相同,則按照試卷編號進一步排序。這樣做可以使後續處理學生答題情況時按照一定順序進行,便於輸出整齊的成績報告。
3 遍歷答題紙進行計分評估
點選檢視程式碼
for (AnswerSheet answerSheet : answerSheets.getSheets()) {
    int score = 0;
    StringBuilder scoreDetails = new StringBuilder();

    // 獲取對應試卷
    TestPaper paper = testPapers.getTestPaperByNumber(answerSheet.getPaperNumber());
    if (paper == null) {
        System.out.println("The test paper number does not exist");
        continue;
    }

    // 獲取試卷的問題分數設定
    List<QuestionScore> questions = paper.getQuestionScores();
    for (int i = 0; i < questions.size(); i++) {
        QuestionScore questionScore = questions.get(i);
        String userAnswer = (i < answerSheet.getAnswers().size())? answerSheet.getAnswers().i:get(i) : null;
        QuestionSet question = questionBank.getQuestionByNumber(questionScore.getNumber());

        if (question!= null) {
            // 處理已刪除的問題
            if (question.isDeleted()) {
                System.out.println("the question " + questionScore.getNumber() + " invalid~0");
                scoreDetails.append("0 ");
            } else {
                // 計分邏輯,根據問題型別和答案情況計分
                String[] correctAnswers = question.getAnswerKey().split(" ");
                List<String> userAnswers = Arrays.asList(userAnswer!= null? userAnswer.split(" ") : new String[0]);

                // 處理多項選擇題
                if (correctAnswers.length > 1) {
                    boolean hasWrongAnswer = userAnswers.stream().anyMatch(ans ->!Arrays.asList(correctAnswers).contains(ans));
                    if (hasWrongAnswer) {
                        System.out.println(question.getContent() + "~" + String.join(" ", userAnswers) + "~false");
                        scoreDetails.append("0 ");
                    } else {
                        boolean allCorrect = userAnswers.size() == correctAnswers.length &&
                                             Arrays.asList(correctAnswers).containsAll(userAnswers);
                        if (allCorrect) {
                            score += questionScore.getScore();
                            scoreDetails.append(questionScore.getScore()).append(" ");
                            System.out.println(question.getContent() + "~" + String.join(" ", userAnswers) + "~true");
                        } else {
                            int halfScore = questionScore.getScore() / 2;
                            score += halfScore;
                            scoreDetails.append(halfScore).append(" ");
                            System.out.println(question.getContent() + "~" + String.join(" ", userAnswers) + "~partially correct");
                        }
                    }
                } else { // 處理單項選擇或填空題
                    if (userAnswer == null ||!userAnswer.trim().equals(question.getAnswerKey())) {
                        System.out.println(question.getContent() + "~" + (userAnswer!= null? userAnswer : "") + "~false");
                        scoreDetails.append("0 ");
                    } else {
                        score += questionScore.getScore();
                        scoreDetails.append(questionScore.getScore()).append(" ");
                        System.out.println(question.getContent() + "~" + userAnswer + "~true");
                    }
                }
            }
        } else {
            // 處理不存在的問題
            System.out.println("non-existent question~0");
            scoreDetails.append("0 ");
        }
    }

    // 獲取學生資訊並輸出成績報告
    Student student = studentMap.get(answerSheet.getStudentId());
    if (student == null) {
        System.out.println(answerSheet.getStudentId() + " not found");
    } else {
        System.out.printf("%s %s: %s~%d%n", student.getId(), student.getName(), scoreDetails.toString().trim(), score);
    }
}
for (AnswerSheet answerSheet : answerSheets.getSheets()) {
    int score = 0;
    StringBuilder scoreDetails = new StringBuilder();

    // 獲取對應試卷
    TestPaper paper = testPapers.getTestPaperByNumber(answerSheet.getPaperNumber());
    if (paper == null) {
        System.out.println("The test paper number does not exist");
        continue;
    }

    // 獲取試卷的問題分數設定
    List<QuestionScore> questions = paper.getQuestionScores();
    for (int i = 0; i < questions.size(); i++) {
        QuestionScore questionScore = questions.get(i);
        String userAnswer = (i < answerSheet.getAnswers().size())? answerSheet.getAnswers().i:get(i) : null;
        QuestionSet question = questionBank.getQuestionByNumber(questionScore.getNumber());

        if (question!= null) {
            // 處理已刪除的問題
            if (question.isDeleted()) {
                System.out.println("the question " + questionScore.getNumber() + " invalid~0");
                scoreDetails.append("0 ");
            } else {
                // 計分邏輯,根據問題型別和答案情況計分
                String[] correctAnswers = question.getAnswerKey().split(" ");
                List<String> userAnswers = Arrays.asList(userAnswer!= null? userAnswer.split(" ") : new String[0]);

                // 處理多項選擇題
                if (correctAnswers.length > 1) {
                    boolean hasWrongAnswer = userAnswers.stream().anyMatch(ans ->!Arrays.asList(correctAnswers).contains(ans));
                    if (hasWrongAnswer) {
                        System.out.println(question.getContent() + "~" + String.join(" ", userAnswers) + "~false");
                        scoreDetails.append("0 ");
                    } else {
                        boolean allCorrect = userAnswers.size() == correctAnswers.length &&
                                             Arrays.asList(correctAnswers).containsAll(userAnswers);
                        if (allCorrect) {
                            score += questionScore.getScore();
                            scoreDetails.append(questionScore.getScore()).append(" ");
                            System.out.println(question.getContent() + "~" + String.join(" ", userAnswers) + "~true");
                        } else {
                            int halfScore = questionScore.getScore() / 2;
                            score += halfScore;
                            scoreDetails.append(halfScore).append(" ");
                            System.out.println(question.getContent() + "~" + String.join(" ", userAnswers) + "~partially correct");
                        }
                    }
                } else { // 處理單項選擇或填空題
                    if (userAnswer == null ||!userAnswer.trim().equals(question.getAnswerKey())) {
                        System.out.println(question.getContent() + "~" + (userAnswer!= null? userAnswer : "") + "~false");
                        scoreDetails.append("0 ");
                    } else {
                        score += questionScore.getScore();
                        scoreDetails.append(questionScore.getScore()).append(" ");
                        System.out.println(question.getContent() + "~" + userAnswer + "~true");
                    }
                }
            }
        } else {
            // 處理不存在的問題
            System.out.println("non-existent question~0");
            scoreDetails.append("0 ");
        }
    }

    // 獲取學生資訊並輸出成績報告
    Student student = studentMap.get(answerSheet.getStudentId());
    if (student == null) {
        System.out.println(answerSheet.getStudentId() + " not found");
    } else {
        System.out.printf("%s %s: %s~%d%n", student.getId(), student.getName(), scoreDetails.toString().trim(), score);
    }
}
遍歷排序後的每一張答題紙:
初始化學生得分score為 0,並建立StringBuilder物件scoreDetails用於記錄每個問題的得分情況。
透過答題紙的試卷編號從TestPapersCollection中獲取對應的試卷,如果試卷不存在則輸出相應提示並跳過本次迴圈。
對於獲取到的試卷,遍歷其所有的QuestionScore物件,獲取每個問題的分值設定:
根據問題編號從QuestionBank中獲取對應的QuestionSet物件,如果問題不存在則進行相應處理(輸出提示並給該問題記 0 分)。
如果問題存在且未被刪除:
對於多項選擇題,先將正確答案和使用者答案都拆分成列表形式,然後透過stream的anyMatch等操作判斷使用者答案是否完全正確或部分正確,根據情況給分並記錄得分細節。
對於單項選擇或填空題,直接比較使用者答案和正確答案是否一致,根據情況給分並記錄得分細節。

最後根據答題紙的學生 ID 從Map<String, Student>中獲取學生資訊,如果學生資訊不存在則輸出相應提示,否則輸出學生的成績報告,包括學生 ID、姓名、每個問題的得分情況以及總分。

Main類

類名:Main
方法:main(String[] args):程式的入口點,負責讀取使用者輸入,根據輸入格式進行相應的處理,如新增問題、試卷、學生資訊、答題卡等,並最終呼叫Evaluation類的方法進行答題卡的處理和評分。

以上是我根據題目相關要求初步設計的類圖和方法的一個大致思路,下面是一個我的詳細類圖:
image
呼叫順序圖如下:
image
SourceMonitor分析結果如下:
image

第五次大作業
7-1 家居強電電路模擬程式-1
分數 75
作者 蔡軻
單位 南昌航空大學

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。

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]表示K1的1引腳,K3的2引腳連線在一起。

約束條件:

本次迭代不考慮兩個輸出引腳短接的情況
不考慮調速器串聯到其他調速器的情況。
不考慮各類控制裝置的並聯接入或反饋接入。例如,
     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一定是最後一個連線的後一項。

家居電路模擬系列所有題目的預設規則:

1、當計算電壓值等數值的過程中,最終結果出現小數時,用截尾規則去掉小數部分,只保留整數部分。為避免精度的誤差,所有有可能出現小數的數值用double型別儲存並計算,不要作下轉型資料型別轉換,例如電壓、轉速、亮度等,只有在最後輸出時再把計算結果按截尾規則,捨棄尾數,保留整數輸出。
2、所有連線資訊按電路從電源到接地的順序依次輸入,不會出現錯位的情況。
3、連線資訊如果只包含兩個引腳,靠電源端的引腳在前,靠接地端的在後。
4、對於調速器,其輸入端只會直連VCC,不會接其他裝置。整個電路中最多隻有一個調速器,且連線在電源上。

根據以上題目我分析得到:
這個題要求我用JAVA來實現一個家居強電電路模擬程式,能夠模擬智慧家居場景下的各種控制裝置(如開關、分檔調速器、連續調速器)和受控裝置(如燈、風扇)的連線、控制以及狀態輸出。透過讀取使用者輸入的裝置連線資訊、控制調節資訊等,構建電路模型並展示各裝置的當前狀態或引數。

下面是我對於類的設計思路以及給出了部分類的程式碼實現:

Equipment抽象類
作為所有具體裝置類的基類,定義了裝置的一些通用屬性(如title用於標識裝置名稱、voltage表示電壓、current表示電流)以及必須由子類實現的抽象方法(getTitle用於獲取裝置標題、showDetails用於展示裝置詳細資訊、turnOff用於關閉裝置功能)。透過這種抽象設計,為不同型別的具體裝置類提供了統一的介面規範,使得程式碼在處理各種裝置時具有一致性和可擴充套件性。

abstract class Equipment {
    String title;
    double voltage;
    double current;

    public double getVoltage() {
        return voltage;
    }

    public void setVoltage(double voltage) {
        this.voltage = voltage;
    }

    public double getCurrent() {
        return current;
    }

    public void setCurrent(double current) {
        this.current = current;
    }

    abstract String getTitle();

    abstract void showDetails();

    abstract void turnOff();
}

CircuitSwitch類
繼承關係:繼承自Equipment抽象類,並實現了Comparable介面。
作用:用於類比電路中的開關裝置。它包含一個私有屬性mode來表示開關的狀態(0 表示開啟,1 表示閉合)。透過建構函式和setMode方法來初始化和更新開關狀態,並根據狀態計算電流值(開啟時電流為 0,閉合時電流等於輸入電壓)。重寫了getTitle、showDetails和turnOff等抽象方法,分別用於獲取裝置標題、按照規定格式(如@裝置標識:turned on或@裝置標識:closed)展示開關狀態以及將開關設定為開啟狀態(即關閉裝置功能)。實現Comparable介面使得可以對開關物件進行比較,比較依據是裝置標題。

class CircuitSwitch extends Equipment implements Comparable<CircuitSwitch> {
    private int mode;

    public CircuitSwitch(double voltage, int mode, String title) {
        this.title = title;
        this.voltage = voltage;
        this.mode = mode % 2;
        this.current = (this.mode == 0) ? 0 : voltage;
    }

    public int getMode() {
        return mode;
    }

    public void setMode(int mode) {
        this.mode = mode % 2;
        this.current = (this.mode == 0) ? 0 : voltage;
    }

    @Override
    String getTitle() {
        return title;
    }

    @Override
    void showDetails() {
        System.out.println("@" + title + ":" + (mode == 0 ? "turned on" : "closed")); // 移除中間的空格
    }

    @Override
    void turnOff() {
        // Functionality to turn off can be implemented here if needed
        setMode(0);
    }

    @Override
    public int compareTo(CircuitSwitch other) {
        return this.title.compareTo(other.getTitle());
    }
}

GearGovernor類
繼承關係:繼承自Equipment抽象類。
作用:用於模擬分檔調速器裝置。
它有一個私有屬性gearSetting表示當前的檔位設定。在建構函式中,根據傳入的檔位值透過setCurrentBasedOnGears方法計算並設定相應的電流值(不同檔位對應不同比例的輸入電壓作為電流)。重寫了getTitle、showDetails和turnOff等抽象方法,其中showDetails方法用於按照@裝置標識:檔位值的格式展示當前檔位資訊,turnOff方法可用於實現關閉裝置的相關邏輯

class GearGovernor extends Equipment {
    private int gearSetting;

    GearGovernor(double voltage, int gearSetting, String title) {
        this.gearSetting = gearSetting;
        this.title = title;
        this.voltage = voltage;
        setCurrentBasedOnGears();
    }

    private void setCurrentBasedOnGears() {
        if (gearSetting == 0) {
            current = 0;
        } else {
            current = voltage * (0.3 + (gearSetting - 1) * 0.3);
        }
    }

    @Override
    String getTitle() {
        return title;
    }

    @Override
    void showDetails() {
        System.out.println("@" + title + ":" + gearSetting); // 移除中間的空格
    }

    @Override
    void turnOff() {
        // Turn off logic if necessary
    }
}

剩下只寫出我設計了哪些類程式碼不作給出:

ContinuousGovernor類

-用於模擬連續調速器裝置。它包含一個私有屬性ratio表示檔位比例。在建構函式中,根據傳入的比例值計算電流值(電流等於輸入電壓乘以檔位比例)。重寫了getTitle、showDetails和turnOff等抽象方法,showDetails方法用於按照@裝置標識:保留兩位小數的檔位比例值的格式展示當前檔位資訊,turnOff方法可用於新增關閉裝置的相關功能。

IncandescentLight類

-用於模擬白熾燈裝置。它有一個私有屬性brightness用於儲存燈泡的亮度值。在建構函式中,根據傳入的電壓值透過calculateBrightness方法計算燈泡的亮度(根據不同的電壓範圍採用不同的計算公式)。重寫了getTitle、showDetails和turnOff等抽象方法,showDetails方法用於按照@裝置標識:亮度值的格式展示燈泡的亮度,turnOff方法用於將燈泡亮度設定為 0,即關閉燈泡。

SolarLight類

-用於模擬日光燈裝置。它包含一個私有屬性brightness用於儲存日光燈的亮度值。在建構函式中,根據傳入的電壓值簡單判斷並設定亮度值(電壓不為 0 時亮度為 180,否則為 0)。重寫了getTitle、showDetails和turnOff等抽象方法,showDetails方法用於按照@裝置標識:亮度值的格式展示日光燈的亮度,turnOff方法用於將日光燈亮度設定為 0,即關閉日光燈。

FanDevice類

-用於模擬風扇裝置。它有一個私有屬性speed用於儲存風扇的轉速值。在建構函式中,根據傳入的電壓值透過calculateSpeed方法計算風扇的轉速(根據不同的電壓範圍採用不同的計算公式)。重寫了getTitle、showDetails和turnOff等抽象方法,showDetails方法用於按照@裝置標識:轉速值的格式展示風扇的轉速,turnOff方法用於將風扇轉速設定為 0,即關閉風扇。

EquipmentCollection類

-用於管理一系列的裝置物件。它內部維護一個List型別的成員變數devices,透過addDevice方法可以向其中新增各種型別的裝置物件,getDevices方法用於獲取儲存的裝置列表,displayAll方法用於遍歷裝置列表並呼叫每個裝置的showDetails方法,從而實現統一展示所有裝置的狀態或引數資訊的功能。

Main類

-建立了一些必要的資料結構,如Scanner用於讀取使用者輸入,Map<String, Integer>用於跟蹤開關狀態變化次數,多個List用於儲存連線資訊、控制命令等。
透過迴圈讀取使用者輸入,根據輸入內容是否包含[或 ``#將其分別新增到對應的connections或commands列表中,直到讀取到end` 為止。
對控制命令列表commands進行解析,針對不同型別的控制命令(開關、分檔調速器、連續調速器)進行相應的處理,如更新開關狀態跟蹤資訊、調整分檔調速器的檔位、設定連續調速器的檔位比例等。
遍歷連線資訊列表connections,透過正規表示式匹配解析出連線的裝置資訊,根據裝置型別建立相應的裝置物件並新增到equipmentCollection中,在建立裝置物件時,會根據前一個裝置的輸出電流作為當前裝置的輸入電壓來構建電路連線關係。
最後呼叫equipmentCollection的displayAll方法,展示所有裝置的狀態或引數資訊。

點選檢視程式碼
public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        Map<String, Integer> switchTracker = new HashMap<>();
        List<CircuitSwitch> switches = new ArrayList<>();
        EquipmentCollection equipmentCollection = new EquipmentCollection();
        List<String> connections = new ArrayList<>();
        List<String> commands = new ArrayList<>();

        while (true) {
            String line = scanner.nextLine();
            if (line.equals("end")) break;

            if (line.contains("[")) connections.add(line);
            else if (line.contains("#")) commands.add(line);
        }

        int governorSettings = 0;
        double continuousRatio = 0;

        if (!commands.isEmpty()) {
            for (String command : commands) {
                if (command.startsWith("#K")) {
                    Matcher matcher = Pattern.compile("#(K[0-9]+)").matcher(command);
                    while (matcher.find()) {
                        String switchName = matcher.group(1);
                        switchTracker.put(switchName, switchTracker.getOrDefault(switchName, 0) + 1);
                    }
                } else if (command.startsWith("#F")) {
                    if (command.contains("+") && governorSettings < 3) governorSettings++;
                    if (command.contains("-") && governorSettings > 0) governorSettings--;
                } else if (command.startsWith("#L")) {
                    Matcher matcher = Pattern.compile("#L[0-9]+:([0-9.]+)").matcher(command);
                    if (matcher.find()) {
                        continuousRatio = Double.parseDouble(matcher.group(1));
                    }
                }
            }
        }

        for (String connection : connections) {
            Matcher matcher = Pattern.compile("\\[VCC ([A-Z0-9]+)\\-1\\]").matcher(connection);
            if (matcher.find()) {
                String name = matcher.group(1);
                switchOrDevice(name, switchTracker, governorSettings, continuousRatio, equipmentCollection);
                continue;
            }

            matcher = Pattern.compile("\\[[A-Z0-9]+\\-2 ([A-Z0-9]+)\\-1\\]").matcher(connection);
            if (matcher.find()) {
                String name = matcher.group(1);
                String deviceType = name.substring(0, 1);
                if (deviceType.equals("K")) {
                    CircuitSwitch newSwitch = createSwitch(name, equipmentCollection);
                    equipmentCollection.addDevice(newSwitch);
                } else {
                    Equipment lastDevice = equipmentCollection.getDevices().get(equipmentCollection.getDevices().size() - 1);
                    switch (deviceType) {
                        case "D":
                            equipmentCollection.addDevice(new FanDevice(lastDevice.getCurrent(), name));
                            break;
                        case "B":
                            equipmentCollection.addDevice(new IncandescentLight(lastDevice.getCurrent(), name));
                            break;
                        case "R":
                            equipmentCollection.addDevice(new SolarLight(lastDevice.getCurrent(), name));
                            break;
                    }
                }
            }
            if (connection.contains("GND")) break;
        }

        equipmentCollection.displayAll();
    }

    private static void switchOrDevice(String name, Map<String, Integer> switchTracker, int governorSettings, double continuousRatio, EquipmentCollection collection) {
        if (name.contains("K")) {
            int switchCount = switchTracker.getOrDefault(name, 0);
            CircuitSwitch newSwitch = new CircuitSwitch(220, switchCount, name);
            collection.addDevice(newSwitch);
        } else if (name.contains("F")) {
            collection.addDevice(new GearGovernor(220, governorSettings, name));
        } else if (name.contains("L")) {
            collection.addDevice(new ContinuousGovernor(220, continuousRatio, name));
        } else if (name.contains("D")) {
            collection.addDevice(new FanDevice(220, name));
        } else if (name.contains("B")) {
            collection.addDevice(new IncandescentLight(220, name));
        } else if (name.contains("R")) {
            collection.addDevice(new SolarLight(220, name));
        }
    }

    private static CircuitSwitch createSwitch(String name, EquipmentCollection collection) {
        return new CircuitSwitch(220, 0, name);
    }
}
以上是我根據題目相關要求初步設計的類圖和方法的一個大致思路,下面是一個我的詳細類圖:

image

呼叫順序圖如下:
image

SourceMonitor分析結果如下:
image

第六次大作業:
7-1 家居強電電路模擬程式-2
相較於第五次大作業,本次多了電阻:
所有開關的電阻為 0,白熾燈的電阻為 10,日光燈的電阻為 5,吊扇的電阻為 20,落地扇的電阻為 20
本次迭代模擬一種落地扇。

工作電壓區間為 [80V,150V],對應轉速區間為 80-360 轉/分鐘。電壓在[80,100)V 區間對應轉速為 80 轉/分 鍾,[100-120)V 區間對應轉速為 160 轉/分鐘,[120-140)V 區間對應轉速為 260 轉/分鐘,超過 140V 轉速 為 360 轉/分鐘(本次迭代暫不考慮電壓超標的異常情況)輸入資訊:

電路中的短路如果不會在電路中產生無窮大的電流燒壞電路,都是合理情況,在本題測試點的考慮範圍之內。
4、輸出資訊:

按開關、分檔調速器、連續調速器、白熾燈、日光燈、吊扇、落地扇的順序依次輸出所有裝置的狀態或引數。每個裝置一行。同類裝置按編號順序從小到大輸出。

輸出格式:@裝置標識+裝置編號+":" +裝置引數值(控制開關的檔位或狀態、燈的亮度、風扇的轉速,只輸出值,不輸出單位)
連續調速器的檔位資訊保留兩位小數,即使小數為0,依然顯示兩位小數.00。
開關狀態為0(開啟)時顯示turned on,狀態為1(合上)時顯示closed
如:
@K1:turned on
@B1:190
@L1:0.60

家居電路模擬系列所有題目的預設規則:
1)當計算電壓值等數值的過程中,最終結果出現小數時,用截尾規則去掉小數部分,只保留整數部分。為避免精度的誤差,所有有可能出現小數的數值用double型別儲存並計算,不要作下轉型資料型別轉換,例如電壓、轉速、亮度等,只有在最後輸出時再把計算結果按截尾規則,捨棄尾數,保留整數輸出。

2)所有連線資訊按電路從電源到接地的順序依次輸入,不會出現錯位的情況。電源VCC一定是第一個連線的第一項,接地GND一定是最後一個連線的後一項。

3)連線資訊如果只包含兩個引腳,靠電源端的引腳在前,靠接地端的在後。

4)調速器的輸入端只會直連VCC,不會接其他裝置。整個電路最多隻有連線在電源上的一個調速器,且不包含在並聯單路中。

電路結構變化:
迭代1:只有一條線路,所有元件串聯
迭代2:線路中包含一個並聯電路
image
設計建議:
1、電路裝置類:描述所有電路裝置的公共特徵。
2、受控裝置類、控制裝置類:對應受控、控制裝置
3、串聯電路類:一條由多個電路裝置構成的串聯電路,也看成是一個獨立的電路裝置
4、並聯電路類:繼承電路裝置類,也看成是一個獨立的電路裝置

本次大作業我在上一次的大作業基礎上重新構造了Equipment類。下面列出了它的屬性和一些方法:
Equipment類
作用:作為一個抽象類,作為其他具體裝置類的基類,定義了一些裝置共有的屬性和抽象方法,用於規範子類的行為。
屬性:

switchstyle:用於表示開關樣式相關的屬性。
voltage:裝置的電壓值。
resistor:裝置的電阻值。
name:裝置的名稱。
contact1、contact2:可能用於表示裝置的連線點等相關屬性。

方法:

getSwitchstyle():獲取開關樣式屬性值。
IfPathway():用於判斷裝置是否構成通路,預設返回false,子類可根據具體情況重寫。
getVoltage():獲取裝置的電壓值。
setVoltage(double c):抽象方法,用於設定裝置的電壓值,子類必須實現。
getResistor():抽象方法,用於獲取裝置的電阻值,子類必須實現。
getContact1()、setContact1(double contact1):用於獲取和設定contact1屬性值。
getContact2()、setContact2(double contact2):用於獲取和設定contact2屬性值。
getName():獲取裝置的名稱。
display():抽象方法,用於展示裝置的相關資訊,子類必須實現。
close():抽象方法,用於關閉裝置或執行相關操作,子類必須實現。

新增的落地扇:
FloorFan類
作用:繼承自Equipment類,表示落地扇裝置,根據設定的電壓值來確定落地扇的轉速。
屬性:

speed:表示落地扇的轉速。

方法:

FloorFan(String name):建構函式,用於建立落地扇物件並設定其電阻值和名稱。
setVoltage(double c):根據傳入的電壓值經過一系列計算來設定落地扇的轉速。
getResistor():重寫父類方法,返回落地扇的電阻值。
display():重寫父類方法,展示落地扇的名稱和轉速值。
close():重寫父類方法,將落地扇轉速設定為0,即關閉落地扇。
compareTo(FloorFan o):實現Comparable介面的方法,用於按照名稱對落地扇物件進行比較排序。
點選檢視程式碼
class FloorFan extends Equipment implements Comparable<FloorFan> {
    private int speed;

    FloorFan(String name) {
        super.name = name;
        resistor = 20;
    }

    @Override
    public void setVoltage(double c) {
        double TF = c - Math.floor(c);
        double TC = Math.ceil(c) - c;
        if (Math.min(TF, TC) < 1e-10) {
            c = Math.round(c);
        }
        if (c < 80) speed = 0;
        else if (c >= 80 && c < 100) speed = 80;
        else if (c >= 100 && c < 120) speed = 160;
        else if (c >= 120 && c < 140) speed = 260;
        else speed = 360;
    }

    @Override
    double getResistor() {
        return resistor;
    }

    @Override
    void display() {
        System.out.println("@" + name + ":" + speed);
    }

    @Override
    void close() {
        speed = 0;
    }

    @Override
    public int compareTo(FloorFan o) {
        return name.compareTo(o.getName());
    }
}

新增了串聯電路相關操作和屬性的類:
Series類
作用:用於表示串聯電路相關的操作和屬性,管理一系列裝置,可進行電壓分配、通路檢查、短路檢查等操作。
屬性:

voltage:串聯電路的電壓值。
name:串聯電路的名稱。
resistor:串聯電路的總電阻值。
list:儲存串聯電路中的裝置列表。

方法:

getVoltage()、setVoltage(double voltage):用於獲取和設定串聯電路的電壓值。
getName()、setName(String name):用於獲取和設定串聯電路的名稱。
VoltageDivision():根據串聯電路的總電阻和各裝置電阻進行電壓分配操作。
getResistor():計算並返回串聯電路的總電阻值。
IfPathway():檢查串聯電路是否構成通路。
Ifshort():檢查串聯電路是否短路。
getList()、setList(List<Equipment> list):用於獲取和設定串聯電路中的裝置列表。
addEquipment(Equipment e):向串聯電路中新增裝置。
getEquipment(int index):獲取串聯電路中指定索引的裝置。
點選檢視程式碼
class Series {
    public double getVoltage() {
        return voltage;
    }

    public void setVoltage(double voltage) {
        this.voltage = voltage;
    }

    private double voltage;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    private String name;

    public void VoltageDivision() {
        double aver = getVoltage() / getResistor();
        for (Equipment e : list) {
            if (e instanceof Switch || e instanceof Governor || e instanceof ContinueGovernor) {
                continue;
            } else {
                e.setVoltage(aver * e.getResistor());
            }
        }
    }

    private double resistor;

    public double getResistor() {
        resistor = 0;
        for (Equipment e : list) {
            if (e instanceof Switch || e instanceof Governor || e instanceof ContinueGovernor)
                continue;
            else
                resistor += e.getResistor();
        }
        return resistor;
    }

    public boolean IfPathway() {
        for (Equipment e : list) {
            if (e instanceof Switch) {
                if (e.switchstyle == 0) {
                    return false;
                }
            } else if (e instanceof Parallel && !e.IfPathway()) {
                return false;
            }
        }
        return true;
    }

    public boolean Ifshort() { // 檢查是否短路
        for (Equipment e : list) {
            if (e instanceof Switch && e.switchstyle == 1) {
                return false;
            }
        }
        return true;
    }

    public List<Equipment> getList() {
        return list;
    }

    public void setList(List<Equipment> list) {
        this.list = list;
    }

    private List<Equipment> list;

    Series() {
        list = new ArrayList<>();
    }

    public void addEquipment(Equipment e) {
        list.add(e);
    }

    public Equipment getEquipment(int index) {
        return list.get(index - 1);
    }
}

Parallel類
作用:繼承自Equipment類,用於表示並聯電路相關的操作和屬性,管理多個串聯電路組成的並聯電路,可進行電壓設定、通路檢查等操作。
屬性:

seriesList:儲存組成並聯電路的各個串聯電路列表。

方法:

Parallel(List<Series> seriesList):建構函式,用於建立並聯電路物件並傳入組成它的串聯電路列表。
setVoltage(double c):根據並聯電路是否通路來設定各串聯電路的電壓並進行電壓分配操作。
IfPathway():檢查並聯電路是否構成通路。
getResistor():計算並返回並聯電路的等效電阻值。
display()、close():重寫父類方法,這裡為空實現。
點選檢視程式碼
class Parallel extends Equipment {
    private List<Series> seriesList;

    Parallel(List<Series> seriesList) {
        this.seriesList = seriesList;
    }

    @Override
    public void setVoltage(double c) {
        for (Series series : seriesList) {
            if (series.IfPathway()) {
                series.setVoltage(c);
                series.VoltageDivision();
            }
        }
    }

    @Override
    public boolean IfPathway() { // 檢查並聯是否通路
        for (Series series : seriesList) {
            if (series.IfPathway()) {
                return true;
            }
        }
        return false;
    }

    @Override
    double getResistor() {
        for (Series series : seriesList) {
            if (series.Ifshort()) {
                return 0;
            }
        }
        double r = 0;
        double R = 0;
        for (Series series : seriesList) {
            if (series.IfPathway()) {
                R += (1.0 / series.getResistor());
            }
        }
        return (1.0 / R);
    }

    @Override
    void display() { }

    @Override
    void close() { }
}

Main類

作用:包含main方法,作為程式的入口點,用於讀取使用者輸入的資訊,建立各種裝置物件並將它們新增到相應的電路(串聯或並聯)中,然後根據使用者輸入設定相關裝置引數,最後檢查電路是否通路並進行相應操作(如分壓、展示裝置資訊等)。
以上是我根據題目相關要求初步設計的類圖和方法的一個大致思路,下面是一個我的詳細類圖:
image

呼叫順序圖如下:
image

SourceMonitor分析結果如下:
image

學習總結
透過本階段的三次題目集練習,我在物件導向程式設計領域取得了顯著的進步,對其核心概念與設計理念有了更為深入且全面的理解。
在物件導向程式設計的實踐中,抽象類與介面的運用成為了我構建靈活且可擴充套件程式碼架構的有力工具。抽象類作為一種特殊的基類,允許我定義一些共性的方法與屬性,這些抽象方法在子類中得以具體實現,從而確保了程式碼的一致性與規範性。透過這種方式,我能夠在多個子類中複用抽象類中定義的通用邏輯,避免了程式碼的重複編寫,極大地提升了程式碼的可重用性。例如,在處理一系列具有相似行為但又存在細微差異的物件時,抽象類能夠精準地捕捉到它們的共性,將其抽象出來並提供一個統一的框架,使得子類可以在這個框架基礎上進行個性化的擴充套件。這種程式碼複用機制不僅減少了程式碼量,降低了維護成本,還使得整個程式碼體系更加清晰易懂,便於後續的開發與維護。

同時,我深刻認識到重複程式碼是程式設計過程中的一大隱患。重複程式碼不僅增加了程式碼的長度,使得程式碼庫顯得臃腫不堪,更重要的是,它顯著提升了維護的難度與成本。每當需要對重複程式碼中的邏輯進行修改時,都必須在多個位置進行相同的操作,這極易導致疏漏與錯誤。因此,我學會了仔細審視程式碼,積極尋找並提取其中的通用邏輯,將其封裝成獨立的方法或類,以便在不同的場景中進行復用。在涉及到重複計算的部分,我也會進行最佳化處理,避免不必要的計算開銷,從而提高程式碼的執行效率。例如,對於一些在多個地方都需要進行的複雜數學運算或資料處理操作,我會將其封裝成一個專門的工具類方法,這樣在需要使用該計算邏輯的地方,只需簡單呼叫該方法即可,既保證了計算的準確性與一致性,又提高了程式碼的執行速度。

正規表示式的學習與應用也是本次練習的一大收穫。正規表示式作為一種強大的文字處理工具,能夠以簡潔而高效的方式匹配和解析各種複雜的輸入字串。在處理使用者輸入、檔案讀取或資料驗證等場景時,正規表示式發揮了不可替代的作用。它使得我的程式碼能夠更加靈活地應對各種不同格式的輸入資料,輕鬆地提取出所需的資訊,並進行相應的處理。例如,在處理使用者輸入的表單資料時,透過使用正規表示式,可以快速驗證輸入的格式是否符合要求,如答題資訊等的格式驗證,大大提高了程式的互動性與資料處理的準確性。

在程式碼編寫過程中,我逐漸意識到設計模式的重要性及其廣泛的應用場景。設計模式猶如程式設計世界中的藍圖,為解決各類常見問題提供了經過實踐驗證的優秀解決方案。例如模板方法模式,它透過定義一個演算法的骨架,將一些步驟的具體實現延遲到子類中,使得子類可以在不改變演算法整體結構的前提下,靈活地定製某些步驟的具體行為。這種模式在處理具有固定流程但部分環節存在差異的業務邏輯時非常有效,能夠顯著提高程式碼的複用性與擴充套件性。又如策略模式,它允許在執行時根據不同的條件選擇不同的演算法或行為策略,使得程式碼能夠更加動態地適應各種變化的需求。透過合理地運用這些設計模式,我能夠將複雜的業務邏輯分解為多個簡單且獨立的元件,每個元件專注於完成特定的任務,從而降低了程式碼之間的耦合度。低耦合的程式碼結構使得各個元件之間的依賴關係更加清晰,易於理解與維護,當需求發生變化時,只需對相關的元件進行修改或替換,而不會對整個系統造成大規模的影響,大大提高了程式碼的靈活性與可維護性。

然而,在實踐過程中我也充分認識到自己的不足之處。異常處理是程式設計中至關重要的一環,但我在之前的程式碼編寫中往往容易忽視。在實際執行環境中,各種異常情況都有可能發生,如檔案讀取失敗、網路連線中斷、資料型別不匹配等。如果沒有完善的異常處理機制,程式很可能會在遇到異常時突然崩潰,給使用者帶來極差的體驗,甚至可能導致資料丟失或系統故障。因此,我學會了在編寫程式碼時,仔細分析每一個可能出現異常的環節,並針對性地新增適當的異常處理程式碼。例如,在進行檔案讀取操作時,使用try-catch塊來捕獲可能出現的IOException異常,並在catch塊中進行相應的處理,如提示使用者檔案讀取失敗的原因,或者提供一些備選的處理方案,確保程式在面對異常情況時能夠保持穩定執行,或者至少能夠給出合理的反饋資訊,告知使用者當前的異常狀態,從而增強了程式碼的健壯性與可靠性。

此外,編寫測試用例與熟練運用除錯工具也是我在本次練習中重點提升的技能。測試用例就像是程式碼的質檢員,能夠幫助我在程式碼開發過程中及時發現潛在的問題與漏洞。透過編寫全面且細緻的測試用例,我可以對程式碼的各種功能模組進行系統性的測試,覆蓋不同的輸入情況與邊界條件,確保程式碼在各種預期與非預期的場景下都能正確執行。在除錯過程中,除錯工具成為了我不可或缺的得力助手。透過設定斷點、逐步執行程式碼、檢視變數值等除錯手段,我能夠深入到程式碼的執行流程中,精準地定位問題所在,並及時進行修復。這不僅提高了我解決問題的效率,還使得我能夠更加深入地理解程式碼的執行機制,從而進一步最佳化程式碼的質量。
編寫程式碼本質上是一個解決問題的過程,而三次題目集的練習讓我學會了如何將一個龐大而複雜的問題逐步分解為更小的、更易於管理與解決的子問題。這種分而治之的策略使得整個程式設計任務不再那麼令人生畏,我可以有條不紊地對每個子問題進行分析、設計與實現,最終將各個子問題的解決方案整合起來,完成整個任務。在這個過程中,我深刻體會到編寫程式碼並非一帆風順,尤其是在除錯和解決bug的階段,往往需要花費大量的時間與精力。有時,一個看似微不足道的bug可能會隱藏在程式碼的深處,需要反覆排查與除錯才能發現。但正是透過這些不斷嘗試與改進的過程,我逐漸培養了自己的耐心與毅力,學會了在面對困難與挫折時保持冷靜,堅持不懈地尋找解決方案,這種心態的轉變對於我在程式設計領域的長期發展具有極為重要的意義。

綜上所述,透過這三次題目集的練習,我在物件導向程式設計的知識與技能方面實現了全面的提升。我不僅熟練掌握了抽象類、介面、設計模式等核心概念與技術的應用,還在程式碼質量、可維護性、健壯性以及問題解決能力等方面取得了長足的進步,這將為我今後在實際開發工作中應對各種複雜的挑戰與多樣化的需求奠定堅實的基礎。

相關文章