OO生存指南P1

寫在OO做業以前

在正式寫oo做業以前,先說一些「廢話」吧,就當是對oo的吐槽。java

事實上,早在大一的時候,據說數分很難,然而事實證實數分並無有讓我通宵的體驗。正則表達式

在大二上的時候有一門課叫祭祖,號稱是第一門給咱們「推背感」的課。可是我也是很好的摸了過去,從P5纔開始通宵。(雖然本菜雞隻是止步於P6而已)編程

早有耳聞北航的oo是一門很是「坑」的課程,開始我還不覺得然。然而當第一週基本啥都沒講就給咱們留了一個多項式相加的做業時,我才意識到事情並無那麼簡單。數組

到第三週的ALS電梯已是須要熬到1點鐘,我一邊血淚控訴oo(罵着我這個版本的eclipse很差用,控訴這門課的難度(心態崩了) )一邊寫代碼debug。直到DDL前一天才解決了全部的bug,設計總算有了眉目。才僅僅通過三週,感受像經歷了什麼大的挫折同樣。(多是由於我太菜了)框架

那麼接下來我再來針對具體的三次做業來寫寫本菜雞是如何在三次做業中survive下來的。eclipse


 

第一次做業:多項式加法

事先聲明的是,在此以前我沒有學習過面向對象的課程,包括暑期的面向對象先導課我也沒有參加。(據說暑期的先導課效果很好,若是當時學習了估計此次做業不是很成問題)函數

甚至我連JAVA都沒有學過,還好在寒假的時候聽了同窗的建議,在網上找了JAVA的學習視頻學習了一段時間。至於學習效果如何,固然是不太好的。由於只是看視頻,沒有動手寫代碼,沒有通過系統的訓練。這樣學習一門語言,每每只是掌握了基本的語法而已。對語言的運用則很成問題。雖然掌握的很差,可是不至於沒法入門,總比零基礎來編寫要好。工具

由於對JAVA面向對象思想理解的不深,致使最後差點寫成了個和C差很少,面向過程的代碼。好在第一次做業比較和藹之處,是PPT上給出了一個大致的框架。根據這個框架來補充代碼,基本上算是勉強實現了面向對象。學習

這裏附上度量分析和類圖測試

度量分析:

 

類圖:

 能夠看出來飄紅的點是圈複雜度,方法則是parsePoly,即將字符串分析出多項式的方法。這個方法圈複雜度高的緣由恐怕是由於沒有使用方便的工具matcher和parseInt來讀取數字,而是使用了很麻煩的方法(即C語言的方法)來讀取,致使這個方法須要的工做太多。

設計思路上徹底與PPT上的框架一致,所以不在此贅述。總的來講,之前沒有接觸過面向對象,第一次做業能按照PPT的指導來寫面向對象,可能算是一個優勢吧。 

代碼反思:

(1)一開始在編寫的時候,根據前輩的慕課教導,使用了正則表達式這一強大而可靠的工具,這點仍是值得慶幸的。若是沒有了解到這個工具,按照狀態機來判斷格式,洋洋灑灑能寫出龐大的代碼量。可是那樣的代碼,不管從可讀性,可靠性,都不如利用正則表達式來的實在。並且用狀態機來寫,不免會出現考慮不周的狀況,從而讓人抓住馬腳。

(2)早在寒假時就接觸到了一句格言「不要重複造輪子」(Stop Trying to Reinvent the Wheel)可能辛辛苦苦碼出來一堆東西,最後發現早有現成的工具讓我來用了。好比此次做業中,讀取數字這一部分,我採用了以下代碼

if(buf[i] == '-') negative = -1;
else
{
    for(current=0;buf[i]>='0'&&buf[i]<='9';i++)
    {
        current = current*10+buf[i]-'0';
    }
}
if(buf[i] == ',')
{
    coeff = current * negative;
    negative = 1;
}        

用negative判斷負號,用for循環讀取數字,活脫脫的一個C語言讀取數字的典範。(事實上我是先寫的C程序,這段基本就是從C代碼複製過來的)這樣寫,雖然沒有問題,可是,一個字,蠢。在拿到第二份做業指導書的時候,要讀取數字,我這時候才發覺用狀態機判斷的麻煩,開始另闢出路(面向百度),知道了用matcher來把字符串轉爲數字。後來發現這種方法的簡單,強大,能輕鬆處理前導0和前導符號,比我用狀態機高到不知道哪裏去了。

此次做業以後,我才發現JAVA比C也是不知道高到哪裏去了,各類內庫函數,用起來都是十分方便。(以前專心致志造輪子的我真是滑稽)

BUG攻防:

雖然公測AK,可是在互測中,個人程序被找出來了bug。發現這個bug的時候我是痛心疾首,怎麼有這麼弱智的bug出現。

這個bug僅出如今最後的輸出階段。我在輸出結果時,用一個for循環遍歷到數組中最高指數的項,判斷到係數不爲0就輸出。以前全部的項是輸出 「(係數,指數),」,在指數最高的項輸出「(係數,指數)」。這樣有個明顯的問題。若是指數最高項係數爲0,那麼最後一項輸出會有一個該死的逗號「,」。出現這種bug,大概是由於線下自測時構造的測試樣例太弱,以至於放過這種低級bug。

而下家的代碼則是公測就出現了問題,互測時由於空多項式處理不當被我找到一個bug。老實說下家的dalao代碼寫的是比我好的,只不過處理的太多太麻煩而忽視了代碼的正確性,而我只是保證了代碼的正確性。

因爲此次題目難度不是很大,因此我僅僅是按照測試樹構造測試集來測試下家。沒有發現其餘錯誤就放棄了,改成查看下家代碼,最後才發現的空多項式處理不當的bug。


 第二次做業:傻瓜電梯

此次做業比第一次的難度增長,我以爲大體是由於下面兩點:一是由於此次做業沒有給出具體的框架,僅僅給出了五個類的設計建議。(我到如今還不知道樓層類有什麼用)因此這纔是真正考驗咱們面向對象能力的一次做業。二是指導書的加量不加價太過明顯,看着指導書就有頭疼的感受,並且此次的內容也抽象的多。通常遇到這種抽象的題目什麼的,我都會先去看樣例,然而指導書的樣例斷絕了個人念頭(你懂的)。萬般無奈下我作出了一個如今看來十分正確和明智的決定:

花了一天來看指導書。不打開eclipse,就是看指導書。從頭至尾,看的迷的地方就再看一遍。

這樣作的好處是,我理解了「我要幹什麼」。

因此此次開始碼以後,沒有由於跟指導書不符而回過頭大幅修改的狀況。早在計組的經驗中咱們就已經得知,不要輕易開始敲代碼,搞清楚設計以後再開始編碼,效率能提高很多。

雖然理解了總體的設計需求,以及有了大致的框架,可是想填滿這五個類仍是不容易的。這時候我使用了計組的ALU策略(計組的時候要搭建CPU,開始不知道幹什麼,因而我從最簡單的ALU寫起,把全部的小部件寫完以後,大致也就清晰了很多)。摸着石頭過河,搞清楚電梯能幹什麼寫出了電梯,按照這個思路把整個補充完了。

可是回過頭來看,第二次做業仍是有不足的地方,因此在第三次做業以前,我修改了第二次做業的設計。由於修改的地方不是不少,這個部分沒有花多長時間,可是爲第三次做業算是作了墊腳石。否則按照我原來的設計,第三次做業估計得寫的麻煩死。修改部分以下:

(1)存儲請求的隊列,本來爲Array數組結構,改成了ArrayList鏈表結構。這樣不管是取出請求,刪除請求,改變請求位置,都簡單了很多。(第二次做業怎麼沒發現這個這麼好用)

(2)第二次做業中,主方法完成了從讀取,到掃描請求隊列,到調度的全部功能。這種設計明顯偏向面向過程,主方法完成了全部功能。因而我把它拆分爲兩個部分。一是讀取輸入,並把合法請求放入隊列中;二是掃描隊列而且調度。並且把判斷同質請求單獨放置了一個方法,這樣就顯得更加符合面向對象的思想。並且對第三次做業的繼承,也能很好的符合需求。

這麼看來,第二次做業的原始稿有些慘不忍睹,因而我在這放出修改版後的類圖和分析。(有些不敢想象原始版本的度量分析是什麼樣的。不過如今也找不到那個版本了)

度量分析:

 

 

 

類圖:

代碼反思:

其實把原來的一個main函數解決到底,改裝成便於第三次做業設計要求的電梯沒花多長時間。可是原來那種設計方式質量仍是慘不忍睹的,而我又沒有優化,把優化時間放在了第三次做業的時候。仍是來看看優化以後的代碼吧。

對標紅的McCabe Cyclomatic Complexity和Nested Block Depth進行分析。

McCabe Cyclomatic Complexity:圈複雜度。圈複雜度太高的緣由是由於scheduler類承擔了太多職能,既要判斷輸入,把合法輸入塞到請求隊列中,又要掃描隊列,調度電梯。還有去除同質請求之類的,這麼看來圈複雜度超限好像還挺正常的。這樣的缺點是代碼很差維護可讀性差,好在此次debug沒花多長時間。

Nested Block Depth:嵌套塊深度。嵌套塊深度表示if,for循環嵌套的個數。這個大抵是由於去除同質請求,每次拿出來主請求以後,要遍歷以後的隊列,這裏就用到了兩個for了。並且每次判斷還有if-else塊,因此致使了嵌套塊深度太高。(我不想說以前用array的版本估計更高。由於每次去掉一個同質請求的時候,只能用for  for來把以後的請求往前挪一位來去除同質請求。還好改爲arraylist了否則怕是藥丸)

總的來講,此次代碼寫完以後基本上沒出什麼bug,再用try-catch來防護代碼,就自覺得大功告成了。然而寫出來的代碼質量確是很低的,也是典型的只爲了正確性拋開了優化設計的典型。事實證實,代碼寫完以後徹底能夠有時間回顧一下寫完的代碼,想一想哪裏能夠優化,爲下一次做業作好鋪墊。

BUG攻防:

公測依然AK,由於此次傻瓜電梯從調度上沒有什麼多的要求,僅僅是判斷完同質請求就搞定了。

然而我仍是太天真了。在bug樹上看到本身的bug時,有一種本身被暗算,被偷襲了的感受。

此次被爆的bug是由於製表符TAB不算空格,而我會把」\\s+"(即全部空白字符)轉爲「」(過濾空格),因而就被爆了一個bug。

測試者把我這個bug報了還在笑,我是笑不出來,眼淚往肚子裏咽。(感受這門課還能鍛鍊心態)

我下家寫的代碼就弱了不少,他第一條專門有判斷是否時間爲0,可是若是非法輸入,會少輸出一行ERROR,因而公測掛了一堆。我也是從這裏找到了他的bug,至於功能性和同質測試完成的仍是不錯的,由於確實不難。

測試策略仍是沿着樹測下來,傻瓜電梯沒有捎帶,構建再強大的測試用例也並無什麼用。

此次bug攻防中我知道了原來這遊戲還有這種玩法?真實面向readme找bug?因此以後寫readme的時候,必定要當心細緻,把全部可能被圖謀不軌的測試者發現的細節問題都考慮到,不在這種莫名其妙的地方被爆bug。不過以後的做業也是愈來愈難,若是仍是在這種地方找bug,那麼我也是

 


 

 第三次做業:ALS可捎帶電梯

此次ALS電梯,寫代碼debug到了一點鐘,星期二晚上才解決全部bug弄出來最終版,設計也算是有了眉目,能夠說是十分辛酸了。

說一下此次電梯做業的時間分佈吧。

1.仍是看指導書,依然花了很多時間。最重要的是弄清楚「什麼是捎帶」,什麼狀況須要捎帶。

2.修改第二次寫的代碼,這部分真的頗有必要。(若是繼承第二次的原版本估計藥丸)

3.寫ALS調度

 耗時最長的固然是第三部分寫ALS,然而前兩部分的時間一樣很重要。修改了第二次做業以後,如何繼承就更加清晰,寫起代碼也就僅僅須要修改調度部分了。然而這個部分則是花了很多精力與時間,包括構思如何處理捎帶,以及在實現過程當中的debug過程。由於構思的一些問題,中間我還回頭修改了一點地方,好在修改的地方很少。

debug途中最難受的地方就是eclips給我帶來的錯誤,我用下面的式子來計算目標樓層。

elv.getOnfloor() + (next_time - get_overtime) * 2;

可是很明顯須要把double類型轉爲int類型,因而我用eclipse的快捷修改,變成了這樣。

elv.getOnfloor() + (int) (next_time - get_overtime) * 2;

乍一看沒有錯誤,結果有一段調試一直過不去,找了半天才發現是int強轉的範圍出錯,應該是這樣。

elv.getOnfloor() + (int) ((next_time - get_overtime) * 2);

像此類的debug過程還有,好比方法名叫sendInLine,調用時變成了sendinLine,等等。可見編碼時的規範性和細節都十分重要。好在大的設計方向沒錯,最終功能性仍是很好的完成了,大概是把請求分了幾類:

1.主請求,即當前請求

2.副請求,即主請求過程當中,可以完成的捎帶請求

3.未完成的捎帶請求(我起名爲undo),即完不成的捎帶請求

總之按照這個思路寫,基本也是按照指導書的要求實現了捎帶。

接下來從度量分析和類圖來反思代碼質量:

度量分析:

 

類圖:

代碼反思:

仍然是圈複雜度和嵌套塊深度,此次因爲功能設計,用了更多for,更多if。問題也很明顯,很不直觀,因此註釋也是成噸成噸的加。

另一個有意思的點是圈複雜度最後的方法,第二次是sendInLine,讀取請求,這裏是由於須要判斷不少不合法狀況因此圈複雜度高。這一次變成了ScanLine,掃描隊列,也就是ALS的核心部分。這部分要實現捎帶,確實有不少須要添加的部分。

其實當時爲了忙着debug實現功能也是寫的焦頭爛額,徹底沒有考慮太多優化部分,想着寫完了就行。回過頭來看此次代碼,寫的是真的差。冗長,繁複。若是不是註釋多我可能以後都不會看懂。只不過有了度量分析以後,可以看得更明白一點。顯著的問題:

1.方法太少,一個方法巴不得能承擔全部職能。好在判斷同質我單獨寫了一個方法。

2.重複冗長。記得寒假在網上找資料學java的時候聽到的一個準則,do not repeat yourself。看下這個代碼徹底就是在repeat myself。包括遍歷找請求的部分,我可能複製了幾遍。雖然複製也就ctrl + c ,ctrl + v,可是代碼質量也下滑了很多。多寫方法,徹底能夠減小代碼量的。

此次代碼是我寫的最不滿意的一次,以後的代碼可能要吸收此次的教訓,多寫方法,少repeat。

BUG攻防:

這一次由於難度大了,本身測試的時間也多了,好在有較強的測試數據幫助我找到了本身的bug,順利的de完。

這一次的測試策略大概是構造一個包含全部狀況的大樣例,而後一次性測試最終結果。若是不一樣的話再從中找出來錯誤之處(我和舍友都是這樣找到了本身的bug)。把功能性測試完,細節都注意到以後纔算本身的debug工做完成。

此次公測仍然AK,互測並無被找到bug。雖然代碼寫的很差,可是所幸沒有bug,這也得益於我以正確度至上的策略。

測試下家的功能性測試跟本身的策略同樣,他也很好的完成了,可見也是下了功夫的。以後再看代碼,找出了正則表達式的bug。

三次測試,下家功能性完成的都很不錯,可是在一些細節會有些問題。好比正則表達式,這部分能夠在線下測試時多下點功夫,在這方面出錯仍是挺惱火的。


心得體會:

大概是一個菜雞的一點感覺:

1.不要拖延。OO給的時間比計組還緊,越早開始越有充裕的時間來應付可能出現的bug或者意外狀況。我比較喜歡預留一天的緩衝時間,星期三提交星期二就要寫完,這樣星期三就能有測試時間和debug時間,不會出現拖到DDL以後的狀況。

2.多用好的工具。菜就要多學習,就拿表達式合法判斷來講,正則表達式就是比狀態機強大;一樣請求隊列ArrayList就是比Array方便。這些東西在網上找一找資料,絕對比閉門造輪子要好。用工具來寫,代碼的質量和可讀性都高於不用工具。

要知道,沒有什麼是度娘不能告訴你的。若是有,那就谷歌。

3.花時間在讀指導書和構造設計是十分值得的,直接上來就寫代碼,可能會出現一個bug改完,又有新的bug出現的問題。讀懂指導書,想好設計思路,絕對不會吃虧的。

4.多學習別人的代碼。尤爲是若是抽到了dalao的代碼,能夠好好的膜了。寫的好的地方也是能夠借鑑的。(直接抄代碼確定是不行的)

5.個人策略是以正確性爲首,不被找出bug爲主要目的。其實一個代碼寫完以後,徹底是有時間能夠反思一下本身代碼的質量。哪裏能夠優化,哪裏重複了,用一部分時間在這上面仍是能收穫很多的。

6.關於互評這點仍是小小吐槽一下吧,畢竟被扣了奇怪的點,不免仍是有點不爽的。這個故事告訴咱們,readme必定要寫的詳細完備,哪怕沒多大問題,若是被有心人找出來扣了分就很差了。畢竟防火防盜防同窗。個人策略是更偏向於花時間測試完善本身的代碼,所以時間也更側重於測試本身的代碼而不是測試別人的代碼。

無論怎樣我以爲面向readme編程,從readme裏面摳錯誤玩文字遊戲的,是有違OO互測機制的初衷的。以後的做業難度愈來愈高,但願這樣的狀況能發生的更少一點。


雖然這三個星期,寫oo做業仍是很是辛苦,可是收穫仍是很多,好比學到了面向對象的思想,好比得到了充實的感受,感受沒有虛度光陰。

 至此OO的第一階段也算是順利經過了,若是拿遊戲打比方,那麼如今也纔是剛剛經過新手村,前往冒險旅途的開始而已,下面的挑戰難度將會更大。

但願本身可以堅持下來,將後面的每一次做業作好。多學,多寫,多想。也但願你們能齊心合力,攜手通關。

畢竟去補給站這事,你們都不想的對吧。

 若是有什麼寫的很差的地方歡迎你們指出。

相關文章
相關標籤/搜索