目錄
1.前言
2.設計與分析
3.踩坑心得
4.改進建議
5.總結
前言
1.知識點:Java中的繼承與多型,抽象類的應用
2.難度:第4次大作業比較難,後面兩次比較適中,可以適應
3.題量:題量正常,與前面三次大作業的題量比較接近
設計與分析
1.第四次大作業
Sca類的bolformat方法:
該方法中包含多個正規表示式匹配判斷,以及一個條件判斷。因此,圈複雜度為 2。
chuanru類的cr方法:
該方法中包含多個正規表示式匹配判斷,以及一些資料處理邏輯。由於具體的判斷和處理邏輯較為複雜,難以準確計算圈複雜度。但可以估計其圈複雜度相對較高。
Data類的fant方法:
該方法中主要是將各種問題新增到一個集合中,圈複雜度相對較低,為 1。
Paper類的相關方法:
gotquestions方法:主要是根據題目號從資料中獲取問題並新增到試卷中,圈複雜度為 1。
fufen方法:根據題目號設定每道題的分數,圈複雜度為 1。
setquestions方法:按照題目號的順序設定試卷中的問題,圈複雜度為 1。
其他部分的程式碼相對較為簡單,圈複雜度較低。
總體來說,這段程式碼的圈複雜度較高,尤其是在chuanru類的cr方法中。這可能意味著程式碼的複雜性較高。
2.第五次大作業
Device類:
setVoltage方法:有一個條件判斷,圈複雜度為 2。
change方法:一個簡單的方法,圈複雜度為 1。
Vol方法:一個簡單的方法,圈複雜度為 1。
ControlDevice類:
繼承自Device類,沒有新增額外的複雜性。
Kg類:
show方法:一個簡單的輸出方法,圈複雜度為 1。
change方法:根據條件改變狀態,圈複雜度為 2。
Vol方法:簡單的電壓輸出,圈複雜度為 1。
Fendan類:
setMap方法:一個簡單的設定方法,圈複雜度為 1。
show方法:輸出當前檔位,圈複雜度為 1。
change方法:根據輸入改變檔位,圈複雜度為 2。
Vol方法:根據檔位計算輸出電壓,圈複雜度為 2。
Lianxu類:
show方法:輸出當前轉速,圈複雜度為 1。
change方法:根據輸入改變轉速,圈複雜度為 2。
Vol方法:簡單的轉速輸出,圈複雜度為 1。
Light類:
lightset方法:一個簡單的方法,圈複雜度為 1。
Blight類:
繼承自Light類,沒有新增額外的複雜性。
Rlight類:
繼承自Light類,沒有新增額外的複雜性。
DiaoDevice類:
繼承自ConledDevice類,沒有新增額外的複雜性。
Series類:
givevol方法:有多個條件判斷和迴圈,圈複雜度較高,可能在 3-5 之間。
Review類:
revi方法:有多個條件判斷,圈複雜度可能在 2-3 之間。
SetDevice類:
setAlldevice方法:有一個迴圈,圈複雜度為 2。
Main類:
主要是讀取輸入和呼叫其他類的方法,圈複雜度相對較低,可能在 1-2 之間。
總體來說,程式碼的圈複雜度主要集中在Series類和Review類的部分方法中,可能需要特別關注這些方法的複雜性和可維護性。其他類的圈複雜度相對較低,較為簡單。
3.第六次大作業
Device類:
setVoltage方法:有一個條件判斷,圈複雜度為 2。
show方法:一個簡單的方法,圈複雜度為 1。
change方法:一個簡單的方法,圈複雜度為 1。
ControlDevice類:
繼承自Device類,沒有新增額外的複雜性。
Kg類:
show方法:一個簡單的輸出方法,圈複雜度為 1。
change方法:根據條件改變狀態,圈複雜度為 2。
Fendan類:
show方法:輸出當前檔位,圈複雜度為 1。
change方法:根據輸入改變檔位,圈複雜度為 2。
Lianxu類:
show方法:輸出當前轉速,圈複雜度為 1。
change方法:根據輸入改變轉速,圈複雜度為 2。
ControledDevice類:
繼承自Device類,沒有新增額外的複雜性。
Light類:
lightset方法:一個簡單的方法,圈複雜度為 1。
Blight類:
繼承自Light類,沒有新增額外的複雜性。
Rlight類:
繼承自Light類,沒有新增額外的複雜性。
Fan類:
Speedset方法:一個簡單的方法,圈複雜度為 1。
Dfan類:
繼承自Fan類,沒有新增額外的複雜性。
Lfan類:
繼承自Fan類,沒有新增額外的複雜性。
Series類:
ssetoff方法:一個簡單的方法,圈複雜度為 1。
setallresistance方法:有一個迴圈,圈複雜度為 2。
setNeedseriesdevice方法:有一個迴圈,圈複雜度為 2。
setdevicevoltage方法:有一個迴圈,圈複雜度為 2。
Parallel類:
setNeedseries方法:有一個迴圈,圈複雜度為 2。
setallparallelresistance方法:有一個迴圈,圈複雜度為 2。
setseriesvoltage方法:有一個迴圈,圈複雜度為 2。
setDevice類:
setallDevice方法:有多個迴圈,圈複雜度較高,可能在 3-5 之間。
Review類:
revi方法:有多個條件判斷,圈複雜度可能在 2-3 之間。
Main類:
主要是讀取輸入和呼叫其他類的方法,圈複雜度相對較低,可能在 1-2 之間。
總體來說,程式碼的圈複雜度主要集中在setDevice類的setallDevice方法和Series類的部分方法中,可能需要特別關注這些方法的複雜性和可維護性。
踩坑心得
-
正規表示式的使用:程式碼中大量使用了正規表示式來匹配不同型別的題目格式,需要注意正規表示式的編寫是否準確、匹配規則是否完整,許多正規表示式都不是單一的,可能出現重複匹配的情況,而這也導致了我後面可能會出現的程式碼邏輯錯誤
這個就是許多正規表示式連在一起,需要將每一個正規表示式都寫準確。 -
資料處理的流程:整個程式碼邏輯比較複雜,涉及到資料的分類、傳入資料庫、試卷和答案的關聯等過程。需要確保資料處理的流程是清晰和正確的,以避免資料處理出現錯誤或混亂。剛開始我在主函式里面類與類的聯絡非常混亂,傳入資料的過程也是非常的亂,甚至有的時候分不清哪個集合裡面裝了什麼資料。
後面我發現了寫主函式不能一口氣寫完,而要一步一步的去將各個類的功能協和起來。
將主函式里面的程式碼進行了分塊,方便資料傳輸。 -
類之間的關係:各個類之間存在繼承關係和依賴關係,我需要確保每個類的屬性和方法都是正確的,各類之間的關係是合理的。特別是在涉及到子類和基類的資料傳遞時,需要注意資料的正確性和一致性。這一點在我傳輸資料的時候深有體會,所以這一問題很快就解決了。
-
異常處理:很多時候答案總是不盡人意,在對異常進行處理的時候,不能想著一步把所有的問題都解決了,而要去一個個的測試,找出每個小問題,不能一下全部解決,這是不現實的。
-
程式碼最佳化和重構:部分程式碼邏輯可能可以進一步最佳化和重構,包括程式碼結構的調整、方法的合理拆分、重複程式碼的提取等,以提高程式碼的可讀性和可維護性。單一原則的問題。
這幾次大作業基本都實現了單一原則。
改進建議
- 程式碼風格和結構最佳化:
- 確保程式碼縮排和格式統一,增加程式碼的可讀性。
- 為類、方法和變數取有意義的名稱,以提高程式碼可理解性。
- 將不同功能的程式碼塊拆分成更小的方法,以提高程式碼的模組化和可維護性。
- 新增必要的註釋來解釋程式碼的作用和實現細節。
在這幾次大作業中我認為可以對程式碼的格式進行進一步的美化,提高可讀性。
- 異常處理:
在這幾次大作業中,可以在幾個關鍵位置新增異常處理來增強程式碼的健壯性:
檔案讀取:在讀取輸入檔案或其他外部資源時,可能會發生檔案不存在、許可權問題或其他讀取錯誤。可以使用try-catch塊來捕獲這些異常,並進行適當的處理,例如輸出錯誤訊息或採取預設行為。
格式判斷:在第四次大作業bolformat方法中進行格式判斷時,如果正規表示式匹配失敗,可能會丟擲異常。可以在try-catch塊中捕獲這些異常,並處理格式錯誤的情況,例如記錄錯誤資訊或提示使用者重新輸入。
資料處理:在處理資料時,可能會遇到各種異常情況,都可以進行相應的異常處理。
例如在第四次大作業中
public int bolformat() {
try {
// 原本的格式判斷邏輯
String regex1 = "#N:[1-9]\\d* #Q:\\S+ #A:[1-9]\\d*";
String regex2 = "^#T:[1-9]\\d*(\\s[1-9]\\d*-[1-9]\\d*)*";
String regex3 = "^#S:[1-9]\\d* \\d{8}(\\s#A:[1-9]\\d*-.*)*";
String regex4 = "^#X:\\d{8}\\s\\w+(-\\d{8}\\s\\w+)*";
String regex5 = "#D:N-[1-9]\\d*";
String regex6 = "^#Z:[1-9]\\d*\\s#Q:.+#A:(\\s?\\S+)+";
String regex7 = "#K:[1-9]\\d*\\s#Q:\\S+\\s#A:\\S+";
if (!(gline.matches(regex1) || gline.matches(regex2) || gline.matches(regex3)
|| gline.matches(regex4) || gline.matches(regex5) || gline.matches(regex6)
|| gline.matches(regex7))) {
System.out.printf("wrong format:%s\n", gline);
return 0;
}
return 1;
} catch (Exception e) {
// 處理異常情況
System.out.println("發生異常: " + e.getMessage());
return -1;
}
}
在上述示例中,使用try-catch塊來捕獲可能丟擲的異常。如果發生異常,將列印異常訊息並返回-1表示格式錯誤。
透過在關鍵位置新增異常處理,可以更好地處理各種異常情況,提高程式碼的穩定性和可靠性。同時,根據實際需求,可以自定義異常類來更具體地處理不同型別的異常情況。
3. 程式碼註釋:
新增更多的程式碼註釋,以解釋程式碼的功能和邏輯。這將有助於提高程式碼的可讀性和可維護性。
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* Sca 類用於判斷輸入的格式是否正確
*/
class Sca {
private String gline; // 儲存輸入的行
/**
* 建構函式
*/
public Sca() {
}
/**
* 設定輸入的行
*
* @param gline 輸入的行
*/
public void setGline(String gline) {
this.gline = gline;
}
/**
* 判斷格式是否錯誤
*
* @return 如果格式正確返回 1,否則返回 0
*/
public int bolformat() {
// 定義正規表示式模式
String regex1 = "#N:[1-9]\\d* #Q:\\S+ #A:[1-9]\\d*";
String regex2 = "^#T:[1-9]\\d*(\\s[1-9]\\d*-[1-9]\\d*)*";
String regex3 = "^#S:[1-9]\\d* \\d{8}(\\s#A:[1-9]\\d*-.*)*";
String regex4 = "^#X:\\d{8}\\s\\w+(-\\d{8}\\s\\w+)*";
String regex5 = "#D:N-[1-9]\\d*";
String regex6 = "^#Z:[1-9]\\d*\\s#Q:.+#A:(\\s?\\S+)+";
String regex7 = "#K:[1-9]\\d*\\s#Q:\\S+\\s#A:\\S+";
// 使用正規表示式匹配輸入的行
if (!(gline.matches(regex1) || gline.matches(regex2) || gline.matches(regex3)
|| gline.matches(regex4) || gline.matches(regex5) || gline.matches(regex6)
|| gline.matches(regex7))) {
// 如果格式錯誤,列印錯誤資訊並返回 0
System.out.printf("wrong format:%s\n", gline);
return 0;
}
// 如果格式正確,返回 1
return 1;
}
}
/**
* Student 類表示學生
*/
class Student {
private String stuid; // 學生 ID
private String stuname; // 學生姓名
/**
* 建構函式
*/
public Student() {
}
/**
* 設定學生 ID
*
* @param stuid 學生 ID
*/
public void setStuid(String stuid) {
this.stuid = stuid;
}
/**
* 獲取學生 ID
*
* @return 學生 ID
*/
public String getStuid() {
return stuid;
}
/**
* 設定學生姓名
*
* @param stuname 學生姓名
*/
public void setStuname(String stuname) {
this.stuname = stuname;
}
/**
* 獲取學生姓名
*
* @return 學生姓名
*/
public String getStuname() {
return stuname;
}
}
/**
* Question 類表示問題
*/
class Question {
int num; // 問題號
String text; // 問題文字
String anwr; // 標準答案
int score; // 分數
/**
* 獲取問題的標準答案
*
* @return 問題的標準答案
*/
public String getPstuanwr() {
return pstuanwr;
}
/**
* 設定問題的標準答案
*
* @param pstuanwr 問題的標準答案
*/
public void setPstuanwr(String pstuanwr) {
this.pstuanwr = pstuanwr;
}
String pstuanwr; // 問題的輔助標準答案
/**
* 建構函式
*/
public Question() {
}
像這樣做到行行都有註釋
4. 命名規範:
遵循一致的命名規範,使程式碼更易於理解。例如,類名使用大寫字母開頭,方法名使用小寫字母開頭,變數名使用有意義的名稱等。
總結
在這幾次的大作業中,我可以學到以下幾個方面的知識和技能:
物件導向程式設計(OOP):程式碼中使用了類和物件以及繼承和多型,體現了 OOP 的思想。透過定義類和建立物件,可以更好地組織和管理程式碼,提高程式碼的可讀性和可維護性。
資料結構和演算法:程式碼中使用了各種資料結構,如ArrayList來儲存問題、試卷和答案等。同時,還使用了一些演算法來處理和操作這些資料,如遍歷ArrayList、查詢匹配的問題等。
檔案操作:程式碼中透過讀取檔案來獲取輸入資料,並將處理後的資料寫入檔案。這涉及到檔案的開啟、讀取、關閉等操作,以及對檔案內容的解析和處理。
異常處理:程式碼中使用了異常處理機制來處理可能出現的錯誤情況,如檔案讀取錯誤、格式錯誤等。透過捕獲和處理異常,可以使程式更加健壯和可靠。
程式碼組織和模組化:程式碼將不同的功能模組封裝在不同的類中,如Sca類用於格式判斷,Data類用於資料儲存等。這種模組化的程式碼組織方式有助於提高程式碼的可讀性和可維護性。
設計模式:雖然程式碼中沒有明顯使用設計模式,但可以從中體會到一些設計原則,如單一職責原則、開閉原則等。透過合理地設計類和方法,使得程式碼更加靈活和易於擴充套件。
資料處理和邏輯判斷:程式碼需要對輸入的資料進行處理和判斷,如判斷格式是否正確、將資料分類儲存等。這涉及到對資料的解析、邏輯判斷和處理能力。
測試和除錯:在實際開發中,測試和除錯是非常重要的環節。透過對程式碼進行測試,可以發現潛在的問題並及時修復,確保程式碼的正確性和穩定性。
總之,這幾次的大作業涵蓋了多個方面的知識和技能,透過學習和理解,可以提升自己的程式設計能力和解決問題的能力。同時,也可以根據實際需求對程式碼進行改進和擴充套件,以滿足更多的功能需求。