第一做業主要是給咱們引入了一個對於非法輸入處理的思想,包括第一次上機,都一直圍繞着一個全新的主題,就是非法輸入處理,而對於此次做業自己,其實難度並非很大,甚至用純C也不會有很大的工做量,可是引入了一個這樣一個重要思想筆者以爲是學到不少的git
提及第一次做業,筆者實際上是有爲第二次做業作準備的(可是看起來準備的並不合格),在第一次做業中筆者還專門準備了一個虛基類來準備繼承其餘的項(由於怕操做失誤刪了),以方便在第二次做業若是加入其餘的函數,就直接加上一個新的子類,而後上層邏輯用利用多態,根本不用改(事實證實是我想少了)。算法
直接上UML圖吧(先讓我去git clone 一下)編程
能夠看到,看到每一個類的方法不少,不過細看能夠看出來不少其實這主要是方法模塊化的結果。設計模式
首先是關於錯誤處理和輸入規範化,筆者單獨實現了一個Parser解析類來完成這個工做,利用正則分割和匹配每一項,在遇到非法輸入即拋出異常,有頂層類捕獲並輸出WF架構
而後就是求導部分,由於只有加法,因此只須要表達式調用每一個項的求導便可完成求導模塊化
最後是化簡,也就是優化,在本章做業裏,優化都是一個讓我以爲很難受的地方,也不必定說每一個優化有多麼複雜的邏輯或是算法,可是更多的給個人感受是,從整理到求導整個過程像是一個總體,而優化就像是沒有關係的一件事情硬插在了裏面。函數
不過如今靜下心來思考,其實,優化不該該被放在任何一個因子、項、表達式類裏面,其實,筆者以爲應該裝飾者模式來處理也許會更好,每種優化做爲一個裝飾者,而後將項、表達式、因子傳入,而後再獲得化簡後的結果,這樣的組織首先不會致使化簡邏輯和運算邏輯混爲一談,兩件事情高度耦合,錯誤就很容易發生(筆者本人也是深受其害,以致於Bug修復的時候只須要註釋掉simplify()
函數就能夠修復絕大多數同質Bug),因此仍是回到了高內聚低耦合的話題上,這件事情應該是設計階段要仔細思考的一件事。oop
因此也能夠看到,個人項和表達式裏面充斥着大量的和項與表達式運算無關的方法,他們也嚴重違反了單一職責原則測試
Class | CBO | DIT | LCOM | NOC | RFC | WMC |
---|---|---|---|---|---|---|
Arithmetic | 3.0 | |||||
Parser | 1.0 | 1.0 | 1.0 | 0.0 | 21.0 | 13.0 |
Poly | 2.0 | 1.0 | 1.0 | 0.0 | 39.0 | 23.0 |
PowerItem | 2.0 | 1.0 | 4.0 | 0.0 | 26.0 | 29.0 |
Solution | 2.0 | 1.0 | 1.0 | 0.0 | 16.0 | 3.0 |
Total | 68.0 | |||||
Average | 1.75 | 1.0 | 1.75 | 0.0 | 21.0 | 17.0 |
從度量中也能夠看到總體複雜度其實仍是不高的優化
第二次相對於第一次,求導規則更加複雜,數據如何組織是一件比較麻煩的事情,因爲當時筆者沒有將常數做爲單獨一項來處理,因此致使在優化合並的時候,提取係數極其困難
直接上類圖,我們看圖說話
很龐大,可是其實就是因子繼承虛基類,而後全部承在一塊兒的因子構成一個所謂的Box,Box中用HashMap來維護三項,主體邏輯跟上一次徹底相同,可是化簡邏輯複雜了不少,從圖中也能夠看到有不少化簡函數放在了裏面,讓人看不懂,這也是這三次做業的敗筆所在,沒有把化簡功能分離出來,這樣不只不利於測試化簡功能,並且程序的未知行爲沒法估測,這也是這樣測試中出現Bug的一個十分重要的緣由
下面給出程序的度量
Class | CBO | DIT | LCOM | NOC | RFC | WMC |
---|---|---|---|---|---|---|
Constant | 1.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 |
ItemType | 4.0 | 1.0 | 2.0 | 2.0 | ||
Solution | 4.0 | 0.0 | 1.0 | 0.0 | 11.0 | 4.0 |
ItemFactory | 6.0 | 0.0 | 1.0 | 0.0 | 5.0 | 9.0 |
TirgoItem | 4.0 | 1.0 | 2.0 | 2.0 | 11.0 | 10.0 |
SinItem | 7.0 | 2.0 | 5.0 | 0.0 | 17.0 | 11.0 |
CosItem | 7.0 | 2.0 | 5.0 | 0.0 | 17.0 | 11.0 |
Item | 7.0 | 0.0 | 8.0 | 2.0 | 15.0 | 12.0 |
Parser | 4.0 | 0.0 | 1.0 | 0.0 | 10.0 | 13.0 |
Poly | 2.0 | 0.0 | 1.0 | 0.0 | 17.0 | 25.0 |
PowerItem | 6.0 | 1.0 | 8.0 | 0.0 | 21.0 | 29.0 |
ItemBox | 9.0 | 0.0 | 1.0 | 0.0 | 22.0 | 44.0 |
Total | 170.0 | |||||
Average | 5.083333333333333 | 0.5454545454545454 | 2.8333333333333335 | 0.36363636363636365 | 11.692307692307692 | 14.166666666666666 |
能夠看到,因爲Poly
和ItemBox
類中集合了過多本不應屬於他們的方法,因此致使這兩個類的複雜度很高,最終的Bug也是出如今這兩個類的協做中
此次的做業看起來改動很大,其實仔細分析能夠發現,只是新增了一個嵌套功能,也就是說,若是保證嵌套的內容沒有問題,那麼整個程序的邏輯和第二次做業基本是一致的,我也是按照這個思路來組織,並根據指導書給出的因子、項、表達式這樣的分層結構來實現的設計
基本就是按照指導書給出的三層結構來實現的設計,下面給出UML圖
結構很清晰,容我再次痛斥一次我這種骯髒的優化設計,耦合度真的很高,沒法測試,致使系統存在大量的不肯定性,正確性沒法保證的同時,還沒法單獨調試改錯,實在醜陋
Class | CBO | DIT | LCOM | NOC | RFC | WMC |
---|---|---|---|---|---|---|
ExceptionUtil | 1.0 | 1.0 | 1.0 | 0.0 | 5.0 | 1.0 |
Main | 4.0 | 1.0 | 1.0 | 0.0 | 12.0 | 2.0 |
PowerFactor | 5.0 | 2.0 | 2.0 | 0.0 | 18.0 | 9.0 |
NumFactor | 7.0 | 2.0 | 2.0 | 0.0 | 17.0 | 9.0 |
Factor | 7.0 | 1.0 | 4.0 | 5.0 | 20.0 | 12.0 |
FactorFactory | 7.0 | 1.0 | 1.0 | 0.0 | 9.0 | 13.0 |
ExprFactor | 5.0 | 2.0 | 4.0 | 0.0 | 22.0 | 15.0 |
CosFactor | 6.0 | 2.0 | 1.0 | 0.0 | 36.0 | 19.0 |
SinFactor | 6.0 | 2.0 | 1.0 | 0.0 | 35.0 | 19.0 |
Term | 13.0 | 1.0 | 1.0 | 0.0 | 51.0 | 49.0 |
Expr | 3.0 | 1.0 | 3.0 | 0.0 | 61.0 | 63.0 |
Total | 211.0 | |||||
Average | 5.818181818181818 | 1.4545454545454546 | 1.9090909090909092 | 0.45454545454545453 | 26.0 | 19.181818181818183 |
能夠看出,底層的模塊的複雜度還較爲良好,而上層的模塊,也就是項和表達式,因爲過多的化簡邏輯摻雜其中,致使這兩個類的複雜度很高,是十分糟糕的狀況
筆者在第二次和第三次都出現了Bug,並且狀況很相似,都是一個幾行代碼就能修復可是卻很致命的Bug,我以爲緣由有下面幾點:
因此我以爲,在設計一個程序的時候,首先,應該保證良好的模塊間解耦,從而可以讓思惟集中而不用去一直全局考慮,其次,就是要合理組織數據,若是要完成的兩件事情有各自的較優數據組織方式,那麼從新組織數據也不失爲一種方法
關於如何發現別人的Bug,我從兩個角度說吧
出於行業內的代碼審查和代碼走查方式:
這種方式強調看代碼邏輯,也就是白盒測試,在看代碼的同時不斷提出疑問,而後從這些疑問中尋找可能存在的bug,黑盒測試在這裏只起輔助驗證做用。
然而,在現有的遊戲模式下,首先,你要面對的是六七份代碼,每份的代碼量都在千行左右,並且有的代碼的可讀性又比較差,畢竟沒有統一的設計規範,這種方法基本不可行,畢竟這種方法在企業中的效率也就只是幾我的兩個半小時幾百行代碼的樣子
因此,萌生了一種很沒趣的方式——評測機玩法
我也叫它搖獎玩法,就是經過本身定義一個生成邏輯,而後模擬評測機去一直測測測,何時測到了就算撈到了,這個方法主要的效果是會給編程人員較大的壓力和動力去完善本身的代碼,對於評測人員,應該能夠提升編寫腳本的能力,可謂收穫頗豐呢
既然說到設計模式了,就簡單提一下
對於本次做業,我以爲有下面這兩種模式都是比較推薦的:
FactorFactory