總結與思考 :OOP課程PTA作業4 - 6

FreeMorty發表於2024-06-07

一. 前言
本次Blog旨在總結物件導向的程式設計的作業,前一題為答題判題程式,後兩題為家居強電電路模擬程式。具體的設計過程和心得如下。
二. 設計與分析
(一) 答題判題程式

  1. 相對上一題迭代的內容
點選檢視題目
本次作業新增內容:

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
20201104 Jack: 0 10~10
2.類設計

相較上次題目我這次設計了MCQ(多項選擇題),繼承自Question類,其實這樣做有點不妥當,應該先定義一個抽象問題類,在擴充出單項選擇題和多項選擇題。對於多選題,透過正規表示式將“ ”,“或”等關鍵詞兩邊的字串進行裁切,儲存在陣列中,以便後續比對。
3.多項選擇題的判分方法

首先檢查學生的答案是否存在(非空)以及問題是否存在。然後根據問題的型別進行不同的判斷:單選題或多選題。
對於單選題,直接比較學生答案與標準答案是否相等,然後根據結果將評判結果記錄到答案物件中。
對於多選題,首先將學生答案和標準答案都分割成單個選項,並進行逐個匹配。如果學生答案中至少包含一個標準答案的部分,或者有一個或多個學生答案匹配了部分標準答案,則認為是部分正確。根據判斷結果將評判結果記錄到答案物件中。
缺陷:使用instanceof,實際上沒有實現狹義上的多型,應該定義一個判分方法,再在不同的類中進行不同的實現。
4.已知的判分的問題

答案和標準答案沒有分塊,如果答案和標準答案出現順序上的問題,可能會導致判分出錯。
我的判斷流程是:
1).標準答案.equal(我的答案)是否成立
2).如果不相等,進行後續操作
某些情況,比如#A:瑤琴或七絃琴 答案為:七絃琴或瑤琴,會先判斷成不是全對,在進行分塊判斷,導致輸出partially correct,但是分數又是全分的情況。
解決辦法:在一開始就將答案分塊,然後判斷自己的答案的陣列的size和標準答案的陣列的size,若相同,在進行遍歷(n*n)比對,如果size不相等,那麼肯定屬於部分正確的情況,在進行後續操作。
5.由答題順序的到的反思:程式的寫法不會有甲方(在本題中就是P他的題目說明)給出完全正確且詳細的設計以及過程,還是應該自己多考慮一些生活實際情況,將實際情況帶入程式設計設計中去。
6.不能過於依靠測試點的提示,針對測試點而修改程式碼,應該在設計時就考慮實際情況,不能抱有僥倖心理,覺得可能不會出現這種***鑽的情況,就放棄這種設計。另外,由於此題取消了測試點的提示,導致我束手無策。我們應該提高自己的測試能力,不能過度依賴給出的測試樣例。
7.複雜度分析如下

相較上次的程式碼來說,這次程式碼已經有很大改觀,只是最大複雜度存在些許問題,應該是題目判分那一塊的問題,若有時間,應該把答案分塊,判斷,記分,輸出,這幾大核心功能分離,而不是圖方便一塊將判斷和記分雜糅在一塊。

(二) 家居強電電路模擬程式
1.題設:

點選檢視題設詳情
智慧家居是在當下家庭中越來越流行的一種配置方案,它透過物聯網技術將家中的各種裝置(如音影片裝置、照明系統、窗簾控制、空調控制、安防系統、數字影院系統、影音伺服器、影櫃系統、網路家電等)連線到一起,提供家電控制、照明控制、電話遠端控制、室內外遙控、防盜報警、環境監測、暖通控制、紅外轉發以及可程式設計定時控制等多種功能和手段。與普通家居相比,智慧家居不僅具有傳統的居住功能,兼備建築、網路通訊、資訊家電、裝置自動化,提供全方位的資訊互動功能。請根據如下要去設計一個智慧家居強電電路模擬系統。

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一定是最後一個連線的後一項。


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

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

2、所有連線資訊按電路從電源到接地的順序依次輸入,不會出現錯位的情況。

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

4、對於調速器,其輸入端只會直連VCC,不會接其他裝置。整個電路中最多隻有一個調速器,且連線在電源上。

 

家居電路模擬系列1-4題目後續迭代設計:

1、電路結構變化:

迭代1:只有一條線路,所有元件串聯
迭代2:線路中包含一個並聯電路
迭代3:線路中包含多個串聯起來的並聯電路
迭代4:並聯電路之間可能出現包含關係

電路結構變化示意圖見圖1。

2、輸入資訊的變化

串聯線路資訊:用於記錄一段串聯電路的元件與連線資訊。

例如: #T1:[IN K1-1] [K1-2 D2-1] [D2-2 OUT]
      #T1:[IN K1-1] [K1-2 M1-IN][M1-OUT D2-1] [D2-2 GND]
並聯線路資訊:用於記錄一段並聯電路所包含的所有串聯電路資訊。

例如:#M1:[T1 T2 T3]
以上格式僅做參考,格式細節可能會調整,以具體釋出的為準。

3、計算方式的變化

迭代1只包含1個受控元件,不用計算電流,之後的電路計算要包含電流、電阻等電路引數。

4、電路元件的變化

每次迭代會增加1-2個新的電路元件。

image.png


圖1:電路結構示意圖


設計建議:

1、電路裝置類:描述所有電路裝置的公共特徵。

2、受控裝置類、控制裝置類:對應受控、控制裝置

3、串聯電路類:一條由多個電路裝置構成的串聯電路,也看成是一個獨立的電路裝置

其他類以及類的屬性、方法自行設計。

2.類設計

電器類設計

控制電器類設計

電路類設立略過
3.設計思路
由於本題為串聯電路,沒有引入電阻值,且只存在1電器+1控制電器的情況,取巧電路設計直接用列表代替,用再分別透過控制電器的引數對整條電路進行電壓的判斷。該方法存在很大弊端,後續如果引入並聯電路,必須重寫程式碼,而不是重構程式碼,且沒有合適的計算方法。
4.靜態分析

程式碼較上一次作業來說,已經有很大進步,各項指標均在合理範圍內。因為註釋掉部分程式碼塊,導致comments爆表。此次將一個操作的執行簡化成多個小操作,大大降低了程式碼複雜度,提高了程式碼可讀性。
5.心得
增大了對正規表示式的運用,就算測試樣例中具有錯誤的輸入,也會透過正規表示式濾出有效的資訊,進行處理。另外,將資訊的處理,資訊錄入,修改進行了分離,程式結構比較有序。
設計原則要時刻運用到實際的編碼編寫中。比如,此次模擬的4檔非線性調速器,不能因為一直升檔而升到5檔,6檔甚至更高檔位去,也不能降到-1檔等不合理的檔位。不能因為題目要求沒有而不考慮這些錯誤輸入的處理,要時刻考慮著未知的bug。
6.不足
對電壓的理解,處理不足,不知道怎樣一個個處理電器的左端電壓,右端電壓,間接導致下一次迭代無法進行。

經過反覆除錯,仍有幾個測試點無法透過,可能是連線順序錯誤或資料取整的問題。

(三) 家居強電電路模擬程式 迭代二
1.增加的題設

點選檢視新增的條件
6)輸入並聯電路資訊

一條並聯電路佔一行,並聯電路由其包含的幾條串聯電路組成,串聯電路標識之間用英文空格" "分隔。

格式:

"#M"+電路編號+":"+”[”+串聯電路資訊+" "+....+" "+串聯電路資訊+”]” 
例如:#M1:[T1 T2 T3] 
該例宣告瞭一個並聯電路,由 T1、T2、T3 三條串聯電路並聯而成,三條串聯電路的 IN 短 接在一起構成 M1 的 IN,三條串聯電路的 OUT 短接在一起構成 M1 的 OUT。 
約束條件:

本次迭代不考慮並聯電路中包含並聯電路的情況,也不考慮多個並聯電路串聯的情況。
本題不考慮輸入電壓或電壓差超過220V的情況。

輸入資訊以end為結束標誌,忽略end之後的輸入資訊。

本題中的並聯資訊所包含的串聯電路的資訊都在並聯資訊之前輸入,不考慮亂序輸入的情況。
電路中的短路如果不會在電路中產生無窮大的電流燒壞電路,都是合理情況,在本題測試點的考慮範圍之內。

本題不考慮一條串聯電路中包含其他串聯電路的情況。例如:

#T3:[VCC K1-1] [K1-2 T2-IN] [T2-OUT K2-1] [K2-2 T1-IN] [T1-OUT GND]
本例中T1\T2兩條串聯電路實際是T3的一個部分,本題不考慮這種型別的輸入,而是當將T1\T2的所有連線資訊直接包含在T3中定義。
下次迭代中需要考慮這種型別的輸入。
4、輸出資訊:

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

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

本次迭代模擬一種落地扇。

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

由於沒有對此題有解法較好的思路,故下文只分析程式碼片段。
2.對於按照一定順序輸入,不要畏懼遍歷陣列或者列表等儲存結構。

為實現題目要求的“按開關、分檔調速器、連續調速器、白熾燈、日光燈、吊扇、落地扇的順序依次輸出所有裝置的狀態或引數。每個裝置一行。同類裝置按編號順序從小到大輸出”,我只好使用多個遍歷查詢,再排序。我以為這會大幅降低程式碼執行的時間,造成程式碼執行超時,心理做了很久的鬥爭,最後實在沒找到解決辦法,只好採用該辦法,結果返現程式碼執行時間並沒有多大影響。

算下來也只有50ms的執行時間差距。所以不要畏懼寫所謂的“屎山程式碼”,老師的多對於結構,演算法的強調導致我舉步維艱,不敢寫程式碼,其實在前期,寫出執行效率差的程式碼遠比寫不出程式碼要強。

三. 總結
1.首先是要將設計原則,和日常生活中的執行規則自然運用到編碼中去,而不是題目有提示才運用設計原則,才聯絡實際生活。
2.對ArrayList,LinkedList,HashSet,LinkedHashSet,TreeSet等容器類的區別和實際運用不是很瞭解,對於資料的儲存一直使用的都是ArrayList,從來沒采用過其他容器,知識瞭解不夠充分。
3.本次實驗強化了對正規表示式的運用,一些常用的字母程式碼的含義已經可以一眼看出。在閱讀其他程式碼時,也可以看出正規表示式會濾出什麼情況的內容。
4.不需要過度考慮程式碼執行的效率問題,很大程度上,能在執行效率差的程式碼上執行比完全不能執行強。
5.使用了介面進行設計,以前都是採用abstract類或者abstract方法進行編寫。實際上介面的功能和他們差不多,實踐方法就是:interface name{
void name ();
}
再在其他的類中implment,再寫出interface中的方法。
6.很多類庫的方法還從來沒用見過,沒有使用過,應該多找相關書籍看一下,瞭解一些基礎知識。

四. 對於課程的建議
增加課堂例項,減少課堂前測,或者將課堂前測改到線上,不要在前測時就勸退學生,讓學生產生畏懼心理。

                          2024年6月7日