JAVA第二次BLOG作業

22207129-杨焱發表於2024-11-22

目錄

前言

設計與分析

PTA第四次作業

PTA第五次作業

PTA第六次作業

踩坑心得

總結

前言

這幾次的大作業總的來說都花了很多的時間,也有做不出來的,但是一直做總能學到一些什麼。每次我認為比較花時間的是怎麼去設計好類,第六次則要想清楚怎麼處理輸入的電器以及電器的電壓、電阻、甚至是電流,因為第六次和第五次不一樣,第五次是隻有串聯,而第六次則是串並混用。使用繼承還是用介面我認為都是可以做的,但有些情況是有更好的選擇,這幾次作業給我的感覺是,測試點要自己找,很多時候測試樣例過了,才有了一些分數。

設計分析

PTA第四次作業

第四次大作業比第三次大作業多了多選題的判題,我對多選題的設計我採用的是繼承Question類,定義了 Question、MultipleChoiceQuestion、FillInBlankQuestion、TestPaper、Student 、ExamSystem和 AnswerSheet 類來儲存題目、試卷、學生和答卷資訊。parseInput 方法解析輸入資訊並儲存到相應的資料結構中。checkTestPaperScores 方法檢查每張試卷的總分是否為100。gradeAnswers 方法對學生的答案進行評判,並生成輸出資訊。在 gradeAnswers 方法中生成答題資訊、判分資訊和提示資訊。
類圖:

順序圖:

設計思路
資料結構設計:
使用字典來儲存題目資訊、試卷資訊、學生資訊、答卷資訊和刪除題目資訊。
題目資訊字典:鍵為題目編號,值為題目物件(包含題目內容、標準答案、題目型別等)。
試卷資訊字典:鍵為試卷號,值為試卷物件(包含題目編號-分值對)。
學生資訊字典:鍵為學號,值為學生名字。
答卷資訊字典:鍵為試卷號-學號對,值為答案列表。
刪除題目集合:包含所有被刪除的題目編號。
功能模組劃分:
輸入解析模組:負責解析使用者輸入的各種資訊,將其轉換成系統內部的資料結構。
試卷檢查模組:檢查試卷總分是否為100分,如果不是則生成警示資訊。
答題判分模組:根據題目資訊和學生的答案計算分數,並生成詳細的答題資訊。
輸出模組:根據系統內部的資料結構生成符合要求的輸出格式。
異常處理:
對於輸入格式錯誤、題目引用錯誤、試卷號或學號引用錯誤等情況,需要設計相應的異常處理機制,確保系統的健壯性。
關鍵步驟
初始化資料結構:
建立題目資訊字典、試卷資訊字典、學生資訊字典、答卷資訊字典和刪除題目集合。
輸入處理:
迴圈讀取輸入直到遇到"end"。
根據輸入的第一字元(如#N、#T、#X、#S、#D)確定輸入型別,呼叫相應的方法處理輸入資訊。
對於題目資訊、試卷資訊、學生資訊、答卷資訊和刪除題目資訊分別進行解析並存入對應的資料結構。
試卷檢查:
遍歷試卷資訊字典,計算每張試卷的總分,如果不是100分則生成警示資訊。
答題判分:
對於每一份答卷,根據試卷資訊中的題目編號查詢題目資訊,對比學生的答案與標準答案,根據題目型別(選擇題、填空題等)的不同計算得分。
特別注意處理被刪除的題目、答案不存在、題目引用錯誤等情況。
生成輸出:
按照題目資訊、答題資訊、判分資訊、刪除題目提示資訊、題目引用錯誤提示資訊的順序生成輸出。
注意輸出順序優先順序為學號、試卷號,按從小到大的順序先按學號排序,再按試卷號。
異常處理:
在解析輸入資訊時檢查格式是否正確,對於格式錯誤的資訊生成錯誤提示。
在處理答題資訊時,檢查試卷號和學號是否存在,對於不存在的試卷號或學號生成相應的錯誤提示。
1.類設計:
Question: 基礎問題類,包含問題的ID、內容、答案和分數。
MultipleChoiceQuestion: 多選題類,繼承自Question,支援部分正確的情況。
FillInBlankQuestion: 填空題類,繼承自Question,支援大小寫不敏感的答案。
TestPaper: 試卷類,包含試卷ID和問題集合。
Student: 學生類,包含學生ID和姓名。
AnswerSheet: 答題卡類,包含試卷ID、學生ID和學生的答案集合。
2.系統設計
ExamSystem 是整個系統的主控類,負責解析輸入資料、管理題目、試卷、學生和答題卡,並進行評分。

3.輸入解析
ExamSystem 提供了一個 parseInput 方法來解析輸入資料。輸入資料包括題目、試卷、學生和答題卡的資訊,每種資訊都有特定的格式識別符號。

題目解析 (parseQuestion):
根據識別符號(#N:、#Z:、#K:)建立不同型別的問題物件。
儲存在 questions 集合中。
試卷解析 (parseTestPaper):
建立 TestPaper 物件,並將題目及其分數新增到試卷中。
儲存在 testPapers 集合中。
學生解析 (parseStudent):
建立 Student 物件,並儲存在 students 集合中。
答題卡解析 (parseAnswerSheet):
建立 AnswerSheet 物件,並將學生的答案新增到答題卡中。
儲存在 answerSheets 列表中。
刪除題目解析 (parseDeletedQuestion):
將已刪除題目的ID儲存在 deletedQuestions 集合中。
4.檢查試卷總分
checkTestPaperScores 方法遍歷所有試卷,檢查每個試卷的總分是否為100分,如果不是,則發出警告。

5.評分答案
gradeAnswers 方法遍歷所有答題卡,對每個答題卡進行評分:

獲取對應的試卷和學生資訊。
遍歷試卷中的每個題目,檢查學生的答案是否正確。
如果答案正確,累加題目分數。
如果是多選題或填空題且部分正確,累加部分分數。
輸出評分結果。

PTA第五次作業

類圖:

順序圖:

  1. 程式碼結構與邏輯
    主要類和方法
    Electric 類:
    屬性:s(裝置型別識別符號)、id(裝置ID)、shuV(電壓)、ofopen(開關狀態)、speed(速度)、lin(連續值)。
    方法:display()(顯示裝置狀態)、regulate(String vs)(調節裝置)、reshuV(double shuop)(設定電壓)、fanhui()(返回裝置型別的優先順序)。
    子類:
    Kaiguan(開關):
    方法:display()、regulate(String vs)、reshuV(double shuop)。
    Fendang(分檔調節器):
    方法:display()、regulate(String vs)、reshuV(double shuop)。
    Lianxu(連續調節器):
    方法:display()、regulate(String vs)、reshuV(double shuop)。
    Baichi(白熾燈):
    方法:display()、reshuV(double shuop)。
    Riguang(日光燈):
    方法:display()、reshuV(double shuop)。
    Diaoshan(吊扇):
    方法:display()、reshuV(double shuop)。
    主函式邏輯
    輸入處理:
    使用 Scanner 讀取標準輸入。
    解析輸入資料,將連線資訊和控制命令分別儲存在 ArrayList 中。
    裝置建立:
    根據連線資訊建立相應的裝置物件,並儲存在 HashMap 中。
    狀態更新:
    根據控制命令更新裝置狀態。
    處理開關的開閉狀態、分檔調節器的檔位變化、連續調節器的值設定等。
    輸出結果:
    將所有裝置按特定規則排序。
    呼叫每個裝置的 display() 方法輸出最終狀態。
  2. 最佳化建議
    異常處理
    輸入驗證:確保輸入資料的格式正確,避免因輸入錯誤導致程式崩潰。
if (!s.startsWith("[") && !s.startsWith("#K") && !s.startsWith("#F") && !s.startsWith("#L")) {
    System.err.println("Invalid input format: " + s);
    continue;
}

程式碼最佳化
提取公共方法:減少重複程式碼,提高程式碼可維護性。

private static String extractDeviceId(String command) {
    Pattern pattern = Pattern.compile("#(.*)");
    Matcher matcher = pattern.matcher(command);
    if (matcher.find()) {
        return matcher.group(1);
    }
    return "";
}

效能最佳化
資料結構選擇:對於大規模資料,可以考慮使用更高效的資料結構,如 TreeMap 或 ConcurrentHashMap。

Map<String, Electric> map1 = new ConcurrentHashMap<>();
3. 擴充套件方向
圖形使用者介面
使用 Swing 或 JavaFX:提供圖形使用者介面,使使用者可以更直觀地操作和檢視電路狀態。

public class CircuitUI extends Application {
    @Override
    public void start(Stage primaryStage) {
        Button btn = new Button("Run Simulation");
        VBox vBox = new VBox(btn);
        Scene scene = new Scene(vBox, 300, 250);
        primaryStage.setTitle("Circuit Simulator");
        primaryStage.setScene(scene);
        primaryStage.show();
    }

    public static void main(String[] args) {
        launch(args);
    }
}

更多裝置型別
新增裝置:可以輕鬆新增更多型別的裝置,只需繼承 Electric 類並實現相應的方法。

class NewDevice extends Electric {
    public NewDevice(String id) {
        super("N", id);
    }

    @Override
    public void display() {
        System.out.printf("@N%s:%.2f\n", id, someProperty);
    }

    @Override
    public void regulate(String vs) {
        // 實現調節邏輯
    }

    @Override
    public void reshuV(double shuop) {
        // 實現電壓設定邏輯
    }

    @Override
    public int fanhui() {
        return 7; // 返回優先順序
    }
}

多執行緒支援
非同步處理:對於複雜的電路模擬,可以考慮使用多執行緒來提高處理速度。

ExecutorService executor = Executors.newFixedThreadPool(4);

for (Electric device : arraylist6) {
    executor.submit(() -> {
        device.display();
    });
}

executor.shutdown();

PTA第六次作業

順序圖

設計思路
類結構
介面和抽象類
Controllable 介面:定義了一個 control(String command) 方法,用於處理控制命令。
Device 抽象類:所有電器裝置的基類,定義了共有的屬性和方法,如裝置ID、輸入電壓、輸出電壓、電阻等。還定義了抽象方法 updateVoltage() 用於更新裝置的電壓狀態。
具體裝置類
Switch(開關):實現了 Controllable 介面,可以切換開閉狀態。
GearSpeedRegulator(分檔調速器):實現了 Controllable 介面,可以調節檔位。
ContinuousSpeedRegulator(連續調速器):實現了 Controllable 介面,可以調節連續值。
IncandescentLamp(白熾燈):根據電壓計算亮度。
FluorescentLight(日光燈):根據電壓確定亮度。
CeilingFan(吊扇):根據電壓計算轉速。
FloorFan(落地扇):根據電壓計算轉速。
電路類
SeriesCircuit(串聯電路):管理一組串聯的裝置,計算總電阻和電流。
ParallelCircuit(並聯電路):繼承自 Device 類,管理一組並聯的串聯電路,計算總電阻和電流。
輔助類
PinandDevice:負責處理輸入資料,建立裝置和電路物件,更新電路狀態,並列印裝置狀態。
inputHandle:負責讀取使用者輸入並呼叫 PinandDevice 的相關方法進行處理。
主要功能
輸入處理:
讀取使用者輸入,解析連線資訊和控制命令。
根據連線資訊建立裝置和電路物件。
根據控制命令更新裝置狀態。
電路連線:
串聯電路:管理一組串聯的裝置,計算總電阻和電流。
並聯電路:管理一組並聯的串聯電路,計算總電阻和電流。
狀態更新:
根據輸入電壓和電路連線關係,更新每個裝置的電壓和狀態。
處理控制命令,更新裝置的狀態。
輸出結果:
按照特定規則排序裝置,並輸出每個裝置的狀態。
詳細分析

  1. 類結構和繼承關係
    Controllable 介面:定義了控制裝置的基本方法。
    Device 抽象類:提供了裝置的基本屬性和方法,定義了抽象方法 updateVoltage()。
    具體裝置類:每個裝置類繼承自 Device 類,實現了 updateVoltage() 方法,並根據需要實現了 control(String command) 方法。
  2. 輸入處理
    PinandDevice 類:
    processConnection_S:處理串聯電路的連線資訊,建立裝置和串聯電路物件。
    processConnection_p:處理並聯電路的連線資訊,建立並聯電路物件。
    createDevice:根據裝置ID建立具體的裝置物件。
    processControlCommand:處理控制命令,更新裝置狀態。
    Update_circuit_resistance:更新電路的總電阻和電流。
    printDeviceStatus:按特定規則排序裝置,並輸出狀態。
    inputHandle 類:
    input:讀取使用者輸入,呼叫 PinandDevice 的方法處理連線資訊和控制命令。
  3. 電路連線和狀態更新
    SeriesCircuit 類:
    total_resistance:計算串聯電路的總電阻。
    setCurrent:設定串聯電路的電流。
    updateVoltage:更新串聯電路中每個裝置的電壓和狀態。
    ParallelCircuit 類:
    total_resistance:計算並聯電路的總電阻。
    updateVoltage:更新並聯電路中每個串聯電路的電流和裝置的電壓和狀態。
  4. 輸出結果
    PinandDevice 類:
    printDeviceStatus:按特定規則排序裝置,並輸出狀態。
    getTypeOrder:獲取裝置型別的優先順序,用於排序。
    最佳化方案:
    異常處理
    輸入驗證:確保輸入資料的格式正確,避免因輸入錯誤導致程式崩潰。
if (!line.startsWith("[") && !line.startsWith("#T") && !line.startsWith("#M") && !line.startsWith("#")) {
    System.err.println("Invalid input format: " + line);
    continue;
}

程式碼最佳化
提取公共方法:減少重複程式碼,提高程式碼可維護性。

private static String extractDeviceId(String command) {
    Pattern pattern = Pattern.compile("#(.*)");
    Matcher matcher = pattern.matcher(command);
    if (matcher.find()) {
        return matcher.group(1);
    }
    return "";
}

效能最佳化
資料結構選擇:對於大規模資料,可以考慮使用更高效的資料結構,如 TreeMap 或 ConcurrentHashMap。

Map<String, Device> devices = new ConcurrentHashMap<>();
擴充套件方向
圖形使用者介面
使用 Swing 或 JavaFX:提供圖形使用者介面,使使用者可以更直觀地操作和檢視電路狀態。

public class CircuitUI extends Application {
    @Override
    public void start(Stage primaryStage) {
        Button btn = new Button("Run Simulation");
        VBox vBox = new VBox(btn);
        Scene scene = new Scene(vBox, 300, 250);
        primaryStage.setTitle("Circuit Simulator");
        primaryStage.setScene(scene);
        primaryStage.show();
    }

    public static void main(String[] args) {
        launch(args);
    }

}
更多裝置型別
新增裝置:可以輕鬆新增更多型別的裝置,只需繼承 Device 類並實現相應的方法。

class NewDevice extends Device {
    public NewDevice(String id) {
        super(id, 0); // 初始電阻為0
    }

    @Override
    public void updateVoltage() {
        // 實現電壓更新邏輯
    }

    @Override
    public void control(String command) {
        // 實現控制邏輯
    }

    @Override
    public String toString() {
        return "@" + id + ":" + someProperty;
    }
}

多執行緒支援
非同步處理:對於複雜的電路模擬,可以考慮使用多執行緒來提高處理速度。

ExecutorService executor = Executors.newFixedThreadPool(4);

for (Device device : sortedDevices) {
    executor.submit(() -> {
        System.out.println(device.toString());
    });
}

executor.shutdown();

踩坑心得

1.一個類和方法只做一件事,做到低耦合,不能牽一髮而動全身
2.在方法中儘量少用選擇語句,如if-else,降低圈複雜度
3.在一些相似的類如果可以抽象出一些共同的屬性和方法,可以適當使用繼承和多型
4.要多去了解Java強大的類庫
5.需要加強自己對演算法的學習
6.使用繼承和多型可以大大降低程式碼複雜度,提高效率

總結

  1. 設計經驗
    類設計與繼承
    抽象類與介面:在第四次作業中,我們使用了抽象類Question和具體子類MultipleChoiceQuestion、FillInBlankQuestion,在第六次作業中使用了抽象類Device和介面Controllable。這些設計模式幫助我們更好地組織程式碼,提高複用性和擴充套件性。
    單一職責原則:每個類和方法只做一件事,保持低耦合。例如,Question類只負責儲存和處理題目資訊,ExamSystem類負責整體流程控制。
    資料結構設計
    字典與集合:使用字典(如HashMap)儲存題目、試卷、學生和答題卡資訊,使用集合(如HashSet)儲存刪除的題目編號。這些資料結構使得資料查詢和管理更加高效。
    多級巢狀結構:在第六次作業中,使用了多級巢狀的資料結構來管理串並聯電路,例如ParallelCircuit類中包含多個SeriesCircuit物件,這種設計能夠靈活地表示覆雜的電路結構。
  2. 實現經驗
    輸入解析
    解析策略:根據不同型別的輸入(如題目、試卷、學生、答題卡、控制命令等),使用不同的解析策略。透過字串匹配和正規表示式提取關鍵資訊。
    異常處理:在解析過程中加入異常處理,確保輸入格式錯誤不會導致程式崩潰。例如,使用try-catch塊捕獲解析異常,並給出友好的錯誤提示。
    功能模組劃分
    模組化設計:將系統劃分為多個模組,每個模組負責一個特定的功能。例如,輸入解析模組、試卷檢查模組、答題判分模組和輸出模組。這種設計使得程式碼結構清晰,易於維護。
    方法拆分:將長方法拆分成多個小方法,每個方法只完成一個具體任務。這樣可以降低方法的複雜度,提高可讀性和可測試性。
  3. 最佳化經驗
    異常處理
    輸入驗證:在解析輸入資料時,確保資料格式正確。例如,使用正規表示式驗證輸入字串的格式。
    錯誤提示:對於格式錯誤或引用錯誤的資料,生成明確的錯誤提示資訊,幫助使用者快速定位問題。
    程式碼最佳化
    提取公共方法:減少重複程式碼,提高程式碼可維護性。例如,提取公共的字串解析方法extractDeviceId。
    資料結構選擇:根據實際需求選擇合適的資料結構。例如,在處理大量資料時,使用ConcurrentHashMap代替普通的HashMap。
    效能最佳化
    多執行緒支援:對於複雜的電路模擬,可以使用多執行緒來提高處理速度。例如,使用ExecutorService非同步處理裝置狀態更新。
    演算法最佳化:最佳化演算法,減少不必要的計算。例如,在計算電路總電阻和電流時,避免重複計算。
  4. 學習心得
    物件導向程式設計
    封裝:將資料和方法封裝在類中,提高程式碼的安全性和可維護性。
    繼承和多型:透過繼承和多型,實現程式碼的複用和擴充套件。例如,Device類的子類可以重寫父類的方法,實現特定的裝置行為。
    資料結構與演算法
    常用資料結構:熟練掌握常用的Java資料結構,如HashMap、HashSet、ArrayList等。
    演算法應用:學會在實際問題中應用合適的演算法,提高程式的效率。例如,使用排序演算法對裝置進行排序。
    Java類庫
    標準庫:熟悉Java標準庫中的常用類和方法,如Collections、Stream、Pattern、Matcher等。