1.前言:
第四次作業難度較前三次更大,新增有多選題、填空題,不僅要考慮錯選(直接錯)、少選(部分錯)和多選(直接錯),還需考慮順序問題(BCD與CBD要求結果相同)這給判斷是否正確的難度增加了一個檔次,同時還出現了多試卷多人答題的情形,雖然刪除了第三次作業中刪除題目的部分,但整體難度仍舊較高,若前幾次作業效果不理想,這次作業更加難以動手。第五次作業是新的題目,與前四次無關,其要求寫家居強電電路模擬程式,該次作業限定條件多,難度小,但也需為後面的作業打好基礎,該次作業只要求一整個串聯,但要把開關、分檔調速器、連續調速器、白熾燈、日光燈、吊扇類先建立好,並確定好繼承關係,串聯類和並聯類暫時不用可搭好框架以備不時之需。第六次作業是在第五次作業基礎上新增並聯物件和串聯物件,還新增了落地扇類,總體難度上升。
2.設計與分析:
第四次作業:
修改輸入提取內容後,修改答案類與答卷類,在主函式中修改答案判斷條件,新增Kquestion與Zquestion類區分多選和填空題,無需多加方法,繼承構造就行,主要用於區分
Kquestion與Zquestion類如下:
點選檢視程式碼
public class Kquestion extends Question {
public Kquestion(int num,String content,String standard_answer){
super(num,content,standard_answer);
}
}
public class Zquestion extends Question {
public Zquestion(int num,String content,String standard_answer){
super(num,content,standard_answer);
}
}
內容乏善可陳,在主函式中修改部分如下:
點選檢視程式碼
int flag=1;
for(AnswerPaper r : listAnswerPaper)
{
flag=1;
for (Paper p:listPaper)
{
if(r.getNum()==p.getNum())
{
flag=0;
for(int i = 0; i < p.getList().size()&& i < r.getList().size(); i++)
{
Question w=p.getList().get(i);
Answer x=r.getList().get(i);
if(w.getNum()==num_of_cut)
{
x.setGrade(0);
System.out.println("the question "+w.getNum()+" invalid~0");
}
else
{
if(p.getHaveque())
{
System.out.print(w.getContent()+"~"+x.getAnswer()+"~");
if(w.getStandard_Answer().equals(x.getAnswer()))
{
System.out.println("true");
x.setGrade(p.getScore(i));
r.setSum(p.getScore(i));
}
else if(w.getStandard_Answer().contains(x.getAnswer()))
{
System.out.println("partially correct");
x.setGrade((int) p.getScore(i)/2);
r.setSum((int) p.getScore(i)/2);
}
else
{
System.out.println("false");
x.setGrade(0);
}
}
else
{
System.out.println("non-existent question~0");
x.setGrade(0);
}
}
}
for(int i = 0; i < p.getList().size() - r.getList().size(); i++)
{
System.out.println("answer is null");
}
int flag1=0;
for(int j = 0;j<listStudent.size();j++){
if(r.getNums().equals(listStudent.get(j).getNum()))
{
System.out.print(r.getNums()+" "+listStudent.get(j).getName()+": ");
for(int i = 0; i < p.getList().size(); i++)
{
if(i < r.getList().size())
{
Answer x=r.getList().get(i);
System.out.print(x.getGrade());
}
else
System.out.print("0");
if(i!=p.getList().size()-1)
System.out.print(" ");
else
System.out.print("~");
}
System.out.println(r.getSum());
flag1=1;
break;
}
}
if(flag1==0)
{
System.out.println(r.getNums()+" not found");
}
}
}
}
if(flag==1)
System.out.println("The test paper number does not exist");
SourceMontor的生成報表如下:
由此可見程式碼任存在許多的不足(方法的功能較為單一、最複雜方法行的數量過高有待最佳化、程式碼中的塊結構相對簡單、註釋少等),第四次作業在第三次作業的基礎上增加了多選題和填空題,導致答案判斷頻頻出錯,另外,作業中還增加了多試卷,多學生,使得順序輸出失敗,且亂序輸入也需新增條件使其順序。這次作業我做出了一部分改進,開始有意識的遵循或運用單一職責原則、開閉原則、迪米特法則。因改動小,時間分配問題,得分很低。
第五次作業:
設定總的父類Equipment,讓裝置分為受控與控制分別繼承,新增各子類,讀取輸入並儲存個部分電器,根據要求進行狀態調整,最後重置輸入、輸出電壓,調整引數,再按要求順序輸出即可。因為只有一條幹路,無需考慮太多情況,只需優先判斷開關狀態,且新增開關開啟時整個電路斷路最優先即可。
主要部分在主函式中其它用電器、控制器大體相同,只展示其一。
Fan(用電器):
點選檢視程式碼
private double speed;
public Fan(double inputV,String name){
super(inputV,name);
this.speed=0;
}
public void setDeviation(double inputV,double outputV){
this.deviation=inputV-outputV;
}
public void setSpeed(){
if(this.deviation<80){
this.speed=0;
}
else if(this.deviation==80){
this.speed=80;
}
else if(this.deviation>80&&this.deviation<=150){
this.speed=80+4.00*(deviation-80);
}
else if(this.deviation>150){
this.speed=360;
}
}
點選檢視程式碼
protected int state;
public Switch(double inputV,String name){
super(inputV,name);
this.state=0;
}
public void setState(){
if(this.state==0) {
this.state = 1;
}
else{
this.state = 0;
}
}
public void setOutputV(){
if(this.state==0){
this.outputV=0;
}
else if(this.state==1){
this.outputV=this.inputV;
}
}
類圖如下:
第六次作業:
第六次作業在第五次作業的基礎上增加了串聯和並聯物件,關鍵點在於將每個電器指向同一個物件再改變狀態,不考慮亂序輸入的情況使得並聯好寫很多,另外新增了電阻,同時電流亦不可少,新增落地扇類,實際可歸於受控類的子類,但由於物件數量增多,數字不再具有唯一性,使得儲存查詢對應難度上升,我就因為指向的物件錯誤導致修改狀態時未修改到正確的物件至錯。
還有註釋問題,時間線長到可以讓人模糊類中方法的作用,新增註釋才可以更好的修改,此次作業使用了許多類,但是並沒有遵守或運用單一職責原則、開閉原則、迪米特法則,且許多判定過程寫在了主方法中,而不是寫在類中作為類的方法,更沒有代理類。因為在敲之前,很多邏輯部分並沒有思考清楚,導致程式碼出現了許多的冗餘及不必要的程式碼,我意識到了寫註釋的重要性。寫註釋不僅有益於在寫程式碼過程中清晰自己的邏輯,更有益於改程式碼過程中讀懂自己之前寫的程式碼。在主函式中的輸出和修改狀態部分,未找到簡便快捷的方法,過多的全迴圈使得程式碼過於浪費空間且耗時,無效迴圈非常多。因介面與抽象類不熟練,未使用。
在串聯類和並聯類中都新增了電器類陣列,將主函式中的提取過程放在了其中,簡化了主函式。
點選檢視程式碼
if (matcher1.find()) {
String name = matcher1.group(1);
String a = matcher1.group(2);
String b = matcher1.group(3);
String c = matcher1.group(4);
Equipment test = new Concatenation(0, name);
test.setEq(b,hmCon,hmPa);
hmCon.put(name, test);
} else if (matcher2.find()) {
String name = matcher2.group(1);
String a = matcher2.group(2);
Equipment test = new Parallel(0, name);
test.setCon(a,hmCon);
hmPa.put(name, test);
點選檢視程式碼
public void setEq(String str,HashMap<String,Equipment> hm1,HashMap<String,Equipment> hm2) {
String test = str.replaceAll("\\[", "").replaceAll("\\]", "");
String str1[] = str.split(" ");
for (int i = 0; i < str1.length; i++) {
Pattern pattern = Pattern.compile("([A-Z])([0-9])-[12]");
Matcher matcher = pattern.matcher(str1[i]);
Pattern pattern1 = Pattern.compile("([A-Z])([0-9])-[A-Z]+");
Matcher matcher1 = pattern1.matcher(str1[i]);
if (matcher.find()) {
String name = matcher.group(1) + matcher.group(2);
String a = matcher.group(1);
if (i == 0) {
if (a.equals("K")) {
Equipment sw = new Switch(this.inputV, name);
eq.add(sw);
} else if (a.equals("F")) {
Equipment bi = new Binning(this.inputV, name);
eq.add(bi);
} else if (a.equals("L")) {
Equipment co = new Coiled(this.inputV, name);
eq.add(co);
} else if (a.equals("B")) {
Equipment la = new Lamp(this.inputV, name);
eq.add(la);
} else if (a.equals("R")) {
Equipment fl = new Fluorescent(this.inputV, name);
eq.add(fl);
} else if (a.equals("D")) {
Equipment fa = new Fan(this.inputV, name);
eq.add(fa);
} else if (a.equals("A")) {
Equipment floor = new Floor(this.inputV, name);
eq.add(floor);
}
} else if (i !=0 ) {
if(!name.equals(this.eq.get(eq.size()-1).getname())){
if (a.equals("K")) {
Equipment sw = new Switch(eq.get(eq.size()-1).getOutputV(), name);
eq.add(sw);
} else if (a.equals("F")) {
Equipment bi = new Binning(eq.get(eq.size()-1).getOutputV(), name);
eq.add(bi);
} else if (a.equals("L")) {
Equipment co = new Coiled(eq.get(eq.size()-1).getOutputV(), name);
eq.add(co);
} else if (a.equals("B")) {
Equipment la = new Lamp(eq.get(eq.size()-1).getOutputV(), name);
eq.add(la);
} else if (a.equals("R")) {
Equipment fl = new Fluorescent(eq.get(eq.size()-1).getOutputV(), name);
eq.add(fl);
} else if (a.equals("D")) {
Equipment fa = new Fan(eq.get(eq.size()-1).getOutputV(), name);
eq.add(fa);
} else if (a.equals("A")) {
Equipment floor = new Floor(eq.get(eq.size()-1).getOutputV(), name);
eq.add(floor);
}
}
else {
}
}
} else if (matcher1.find()) {
String name1 = matcher1.group(1) + matcher1.group(2);
String a1 = matcher1.group(1);
if (i == 0) {
if (a1.equals("T")) {
Equipment con = new Concatenation(this.inputV, name1);
eq.add(con);
} else if (a1.equals("M")) {
Equipment pa = new Parallel(this.inputV, name1);
eq.add(pa);
}
}
else if(i != 0 && !name1.equals(eq.get(eq.size()-1).getname())) {
if (a1.equals("T")) {
Equipment con = new Concatenation(eq.get(eq.size()-1).getOutputV(), name1);
eq.add(con);
} else if (a1.equals("M")) {
Equipment pa = new Parallel(eq.get(eq.size()-1).getOutputV(), name1);
eq.add(pa);
}
}
}
}
int j=0;
for(String key:hm1.keySet()) {
if(this.eq.get(j).getname().equals(key)) {
this.eq.set(j, hm1.get(key));
}
j++;
}
j=0;
for(Equipment t:eq) {
for(String key:hm2.keySet()) {
if(t.getname().equals(key)) {
this.eq.set(j, hm2.get(key));
}
j++;
}
}
}
點選檢視程式碼
public void setCon(String str,HashMap<String,Equipment> hm){
String test = str.replaceAll("\\[", "").replaceAll("\\]", "");
String str1[] = str.split(" ");
for(int i = 0; i < str1.length; i++) {
Pattern pattern = Pattern.compile("(T[0-9])");
Matcher matcher = pattern.matcher(str1[i]);
if (matcher.find()) {
String name = matcher.group(1);
Equipment con = new Concatenation(this.inputV, name);
eq.add(con);
}
}
int j=0;
for(String key:hm.keySet()) {
if(this.eq.get(j).getname().equals(key)) {
this.eq.set(j, hm.get(key));
}
j++;
}
}
由主要的三個函式和總體來看,不足還是有很多。
根據此報表,以下是改進方向:
減少方法呼叫:方法呼叫可能會導致程式碼執行效率降低。嘗試合併或簡化方法呼叫,以減少方法的呼叫次數。
增加註釋:註釋嚴重不足,有很多的空間來新增註釋,從而提高程式碼的可讀性和維護性。
控制方法複雜度:平均每方法語句數過多,這可能表明某些方法過於複雜。嘗試分解這些方法為更小的、更專注的部分。
管理塊深度:最大塊深度為太大,這可能會影響程式碼的效能。最佳化塊結構,使其更加扁平化,以減少執行時間。
使用介面以簡化程式碼。
類圖如下:
採坑心得:
第四次作業:
多選題答案若為ABCD,作答為AC,直接用contains識別不出部分正確,AB可識別(字串相連才可直接用,否則用多迴圈)。
第五次作業:
注意分檔調速器擋位可加可減
輸出時要按題目要求的順序輸出,不可只按線路順序輸出
在調整開關時,幹路開關斷一個,整個線路斷路
第六次作業:
在並聯提取時,傳前面記錄的串聯電路,以指向同一物件,否則後面開關轉換無法深入到真正的開關
輸出時對每一種電器內部排序
修改狀態時的優先順序按先開關後按線路順序
改進建議:
寫程式碼時提前畫好類圖以減少遺漏。
排序優先於修改狀態更好
多考慮優先順序問題,先將預定狀態確定後再傳電壓
總結:
1.學到了:
Java基礎語法
封裝、繼承、多型的實現(結構體實現封裝,組合實現繼承,介面實現多型)
介面的定義和實現(一個類可以實現多個介面 使用關鍵字interface來定義介面。)
抽象類和介面的區別
ArrayList、LinkedList、HashMap的使用方法
2.需要進一步學習及研究:
在寫程式碼之前,要將整個程式碼的邏輯部分設計好,避免出現寫到中途手忙腳亂的現象。
提升程式碼的可複用性,注重設計中的開閉原則。
每次寫完程式碼都會出現陣列越界的情況,原因大概是思考邏輯時,無法面面俱到。多敲程式碼以提升自己的思考能力以及邏輯能力。畫設計圖、類圖是個不錯的選擇。
在物件傳遞與賦值時找錯物件,畫出空間概念圖可避免
3.建議:
希望能有完整的思路和過程展示,以供觀摩
希望測試點點明測試方向。
希望挑出常用的難點講