第一次作業 第一作業的主要難度在於判斷字元串的格式。在寫C語言代碼時發現,如果輸出格式錯在哪裡內容非常多,導致C語言雖然沒有仔細debug,但依然寫了好久。java使用正則表達式後可以簡化很多,但輸出錯在哪裡要增加的內容更多,所以只是對錯誤簡單地進行分類輸出。 正則表達式相關的類由Matcher和P ...
第一次作業
第一作業的主要難度在於判斷字元串的格式。在寫C語言代碼時發現,如果輸出格式錯在哪裡內容非常多,導致C語言雖然沒有仔細debug,但依然寫了好久。java使用正則表達式後可以簡化很多,但輸出錯在哪裡要增加的內容更多,所以只是對錯誤簡單地進行分類輸出。
正則表達式相關的類由Matcher和Pattern兩個,所用方法:
1. match:如果匹配出的串太長會棧溢出,最終沒有使用
2. find:每次只找出一個合法多項式就不會太長了,還可以用來將數字提取出來
3. group:用捕獲組(就是按模式串中的左括弧位置取出串)取數字更方便些
正則還有不少可用的東西,在以後的學習過程中還要繼續熟悉。
關於類的設計,第一次的實踐表現一般,由於任務簡單,並沒有變紅的metric,圈複雜度壓線合格。但還是由一些不合理的地方。其實可以把輸入和計算功能分別獨立成一個類而非都作為主類的方法以實現功能分離。
(下載插件費了好大力氣,看了好幾個教程,最後還是靠室友幫忙,簡直懷疑是不是受了軟體安裝失敗的詛咒)
debug:一個相當普遍的問題是輸入為空時的問題。雖然最開始是因為系統有些問題導致輸入為空時似乎輸入了null而非空串(原理我不懂只是道聽途說,不過不少人為此加了hasNextLine的判斷),但系統改好之後空串依然是問題,我就發現了這樣一個crash。
第二次作業
第二次作業要求實現規定的5個類,也就是幫忙完成了設計類的任務。這次的主要問題在於判斷同質。我最終用六個類完成了任務(多了Main類,把main放到調度器里一堆static,很難受)。
最開始打算每次執行到下一個任務發生的時間,任務分為在隊列中,已經發出等待執行和正在執行三種狀態,可以直接看任務發出時刻的情況。結果實現的時候沒寫好狀態轉移過程(請求傳丟了),修修補補過程中代碼變得有些亂。
後來發現記錄每類任務的上次完成時間就可以方便地判斷是否是同質請求,就重新寫了一遍。好實現的東西好debug,我沒被找到bug,我匹配到的代碼也是這麼寫,然後我也沒找到bug。然而這樣寫沒有可擴展性,導致我第三次作業繼承的時候只繼承了輸入相關內容和屬性,控制部分的代碼一點都沒用上。
第二次作業的圈複雜度就開始出問題了。我的類分為Building(樓層類,把各樓層及其中人當作一個整體,所以它負責輸入),Request(請求類,將請求的三個東西放一起,簡陋但還挺有用的),ReqQue(請求隊列,先入先出,用的是庫,後來感覺不如arraylist自由,當初因為第一次作業最開始說不讓用沒敢用),Controller(調度器,寫完了才發現名字叫schedule),Lift(電梯,實現的功能是完成當前任務)。
Building的輸入由於分ER,FR兩種分支較多,圈複雜度偏高(17),不過將提取出三個數(終點,時間,請求類型)後的判斷分出來後就問題不大了。其他方法最大的圈複雜度也只有7了。
第三次作業
第三次作業的主要問題在於捎帶。之前的方法雖然簡單,但在這次轉移失敗了。發現又要回歸到類似第二次作業最開始的實現了。電梯正在執行的任務由一個變成多個,等待執行的部分不再是隊列而是會從中間抽取的。電梯每次執行一個操作(0.5秒走一層或1.0秒一次開關門),如果沒有任務就跳到下一個任務的時間(不然執行不到發出時間極限晚的任務)。這次先想明白了任務轉移的過程再開始寫的,沒再出問題。
這次的圈複雜度情況就比較糟糕了,有兩個特大型的方法,邏輯複雜達到合理值的二倍多。但我發現我還可以搶救一下:這兩個方法是由幾個可以立刻分開的東西組成的,它們的功能不夠內聚。ALS_Ctrl的run方法可以將輸入過程和從待執行任務轉到執行中的過程分出來。(這裡突然發現現在的任務隊列ReqQue其實沒什麼用,與待執行集合wait相關的任務都交給ReqQue執行好像更合理,隊列乾脆換成數組或arraylist,但這樣調用的深度又增加了,在Main -> ALS_Ctrl -> Lift -> Request中間又插入了ReqQue,深度好像還行但逼近不合理了)。getIn和第二次作業一樣將提取信息後的判斷分出來就好多了。goOneStep還好。至於canCarry我明明就只就是把指導書的要求翻譯了一下,救不出來了。。。
輸出的順序是這次比較容易出的bug,因為會有之前不捎帶的任務變成捎帶。為瞭解決這個問題採用了室友的方案:每次在已經發出的指令中找到最遠的ER類的任務,更新終點但不添加任務,之後將可捎帶任務加入。這樣就可以不用單獨存主任務了,也省去了按輸入順序標號再排序的過程。
總結
1. 實現問題。直接將引用返回這件事情知道上課聽到之前都完全沒意識到這是個問題。應該改成return x.clone();這種寫法才相對安全些。寫代碼的時候完全沒有圈複雜度的概念,就只是憑感覺地劃分代碼,所以並沒有較好地滿足這個代碼規範。以後實現時要註意。
2. debug。主要依靠測試數據找bug,和身邊的同學合作構造測試集,到第三次的時候還有大佬搭的網站(orz)。代碼也會看,但是結果上基本都是靠數據找到了bug(這個時候倒是能看出代碼哪裡有問題了。。。真是呆)。可能因為大家的代碼基本都比我長(有時會出現我二倍長的代碼),我看了類名,方法名,屬性名,幾行代碼,然後就覺得挺好的應該沒啥了。還是要有耐心一點一點讀代碼才能提高吧。
3. 可擴展性。第三次作業時充分地感受到了實現的方便和可擴展性的矛盾。之前的代碼要麼是模板,每次都直接抄上去調用,一點都不用變,要麼是寫完了就再也不需要的代碼。為了好寫好調少幹活(就是懶,也沒幹得快多少。。),我會儘量挑代碼少的方式,沒考慮採用有了新的需求好改的方式,導致第三次的電梯調度要從頭構思,只有輸入和一小部分代碼留下了,剩下的都在重寫中消失了。這次的不單獨存主任務,用ER指令更新的策略不知會不會對之後的多線程造成不好的影響。以後要格外註意可擴展性了。