OO第一單元總結

OO第一次單元總結

​ 前三次的OO做業的內容總的來講都是圍繞着多項式求導,從最簡單的x的冪函數的求導逐漸增長難度,最後完成含有三角函數和嵌套因子的多項式求導。可是在這三次的程序編寫和debug中,我也出現了大大小小的問題,因此在此,我對於OO前三次做業的完成作一個總結,使本身對於存在的問題可以認識得更加清晰。java


第一次做業

(1)整體歸納

  • 題目要求正則表達式

    簡單多項式求導,多項式的每一項中只含常數和x的冪函數。編程

  • 思路數組

    在第一次做業中,多項式的構造比較簡單,因此在這個時候爲了更加直觀、方便,我選擇了正則表達式做爲主要的工具對於多項式的每一項進行獲取(這也爲第三次做業遇到的困難埋下了伏筆),具體的正則表達式以下模塊化

    (第一項符號比較特殊,單獨判斷)函數

    第一項的正則表達式:工具

Pattern p0 = Pattern.compile(
                "([+-]?[ \\t]*)([+-]?)(\\d*)([ \\t]*[*]?)" +
                  "([ \\t]*x?)" + 
                  "((?:[ \\t]*\\^[ \\t]*[+-]?\\d+)?)");
        Matcher m0 = p0.matcher(str);

​ 其餘各項的正則表達式:學習

Pattern p1 = Pattern.compile(
                "([+-][ \\t]*)([+-]?)(\\d*)([ \\t]*[*]?)" +
                        "([ \\t]*x?)" + 
                    "((?:[ \\t]*\\^[ \\t]*[+-]?\\d+)?)");
        Matcher m1 = p1.matcher(str);

​ (以上正則表達式中存在對於空格的判斷問題,在bug分析部分將會具體分析)測試

​ 在分離出每一項以後,開始進行常規的求導得到每一項求導後的係數和冪指數,最後將這些結果存入一個ArrayList中(同時進行合併同類項),最後進行輸出。優化

  • 優化

    由於此次做業中只包括常數項和x的冪指數項,因此在優化上主要進行了常數項的合併以及冪指數相同的項係數的合併。

(2)基於度量分析程序結構

  • 整體結構介紹

    因爲第一次做業須要完成的實現比較簡單,而且在OO學習的開始面向對象的思想尚未創建起來,因此在第一次做業中我主要仍是按照計算過程建了四個類,分別進行每一項的提取、求導、計算長度,以及結果的輸出。

  • 類圖

    從類圖中能夠看出,程序主要仍是以面向過程的開發爲主,而且沒有更具體細化每個類的功能。

  • 主要度量圖

    由度量圖能夠看出,在代碼中的一些方法中,ev(G)和v(G)的值過大,說明這些方法的非結構化程度較高、獨立路徑過多,這也爲代碼以後的維護帶來了困難。除此以外,代碼中的類的WMC值廣泛偏高,PolyDiff類的Ocavg值也偏高,這也代表着代碼的複雜度太高,代碼在設計上存在很多不合理的地方。

(3)bug分析

  • 本身出現的bug

    在第一次做業中,個人程序所有栽在了空格的識別上。

    1. 沒有正確理解指導書的含義,沒有在識別空格時將除<space>\t的空格判斷出來;
    2. 在其中一處正則表達式中忘記加入\\s*.

    其實上述的錯誤都是一些因爲理解或粗心而形成的錯誤,這也充分體現出了我在寫代碼時對於尋找本身的bug過於忽視,想固然地認爲程序已經達到本身的預期效果。須要警醒!!!

  • 他人的bug——以此爲戒

    因爲第一次的做業比較簡單,因此你們的bug都屬於比較粗心的錯誤(好比容許指數中負號與數字間有空格),主要引起這些錯誤的緣由仍是由於對於指導書的理解不足。這也體現出了理解題意的重要性,而且在寫程序前也應該先預計好可能引起bug的數據從而更好地避開這些致命的小bug。


第二次做業

(1)整體歸納
  • 題目要求

    對於含有常數、x的冪函數、sin(x)的冪函數、cos(x)的冪函數的多項式進行求導。

  • 思路

    因爲第二次做業的因子只有固定、較爲規則的四種類型,因此我在最開始讀入多項式時將全部的項分爲了四個部分,並運用了一個數組存入每一個項分別的整個項的係數、x的指數、sin(x)的指數、cos(x)的指數(這也使第三次做業須要從新進行構造)。接着經過求導的公式,對於每一項進行求導,最終獲得一個ArrayList並將其輸出。

    下面是正則表達式的格式(此時已經去掉了表達式中的空格)(因爲排版問題,正則表達式的格式可能出現問題):

    String teststr1 = "[+-](?:(?:[+-]?[+-]?\\d+)|(?:                       [+-]?" +
                    "(?:(?:sin\\(x\\))|(?:cos\\(x\\))|x)                       (?:\\^[+-]?\\d+)?))";
    String teststr2 = "\\*(?:(?:[+-]?\\d+)|" +
                    "(?:(?:(?:sin\\(x\\))|(?:cos\\                     (x\\))|x)(?:\\^[+-]?\\d+)?))";
    String teststr = teststr1 + "(?:" + teststr2 + ")" +               "*";
    Pattern p = Pattern.compile(teststr);
    Matcher m = p.matcher(str);
  • 優化

    值得注意的是,此次做業中的sin(x)和cos(x)的格式都很是固定,因此還能夠對於$sin(x)^2+cos(x)^2=1$進行化簡。在此個人化簡策略是在將每一項求導結果加入最終的list的時候就經過查找將符合$sin(x)^2+cos(x)^2=1$的輸出項合併,所得新的項在此進行list的插入操做,運用一個遞歸將最終輸出的內容儘量化爲最簡。

(2)基於度量分析程序結構

  • 整體結構介紹

    在本次做業中,我創建了五個類,分別進行輸入、輸出、提取項、提取因子、對於因子進行求導等操做。可是能夠看出,在編程思想上此次做業仍是受到了不少面向過程的思想,而且程序的複用性極差。

  • 類圖

    在本次做業中總共創建了5個類,可是每一個類的功能仍是不夠具體,這也致使在下一次做業中沒法對於這些類進行沿用。

  • 主要度量圖

    由此次做業的度量圖中能夠看出方法PrintPart和InsertList的複雜度都太高,這也與其內部帶有遞歸相關。同時對於類的複雜度,能夠明顯地看到DealWithPoly類的複雜度太高,這也是因爲在DealWithPoly類中進行輸出時運用過多判斷語句,使代碼過於冗長。

(3)bug分析

  • 本身的bug

    在第二次做業中總共出現了兩個bug:

    1. 第一個bug爲輸出格式錯誤,錯誤在輸出中換行了,主要爲粗心和測試不全面而產生的問題;
    2. 第二個bug因爲沿用了第一次的求導方法而產生的錯誤:在第一次做業中,因爲最終結果不會出現x^-1,因此在輸出中我直接將x^-1做爲0輸出,這種方法在第一次做業的處理中當然簡便,然而對於第二次做業倒是致命的,由於在第二次做業的結果中會存在x^-1,然而這樣的操做卻忽視了全部含有x^-1的輸出項。
  • 他人的bug

    此次互測中我發現的他人的bug只要仍是格式判斷的錯誤,其緣由仍是沒有對於指導書中的格式要求考慮全面。


第三次做業

(1)整體歸納

  • 題目要求

    此次做業的主要要求還是進行多項式求導,主要的求導部分還是常數、x的冪函數、三角函數的冪函數。可是不一樣之處在於在此次做業中加入了嵌套因子以及表達式因子,表達式的讀取方式需變爲一種遞歸處理。

  • 思路

    剛開始拿到題目時,本身一直在思索應該怎麼運用正則表達式來表示出表達式的形式從而判斷表達式的格式是否正確,可是苦苦思索無果(java的正則表達式中沒法進行遞歸,且運用正則表達式定會爆棧)。最終,經過理解指導書中推薦方法以及討論區大佬們對題目的理解,我決定放棄掉在前兩次做業中均使用到的長正則表達式,決定使用其餘的方式來判斷表達式格式是否正確,如判斷括號、在局部運用小正則進行特殊格式判斷。

    判斷格式是否錯誤的正則表達式舉例:

    Pattern p = Pattern.compile("\\*[\\+-]+(?:x|s|c)");
    Matcher m = p.matcher(str);
    
    Pattern p1 = Pattern.compile("\\*[\\+-]{2,}\\d+");
    Matcher m1 = p1.matcher(str);
    
    Pattern p2 = Pattern.compile("\\^[\\+-]{2,}\\d+");
    Matcher m2 = p2.matcher(str);
    
    Pattern p3 = Pattern.compile("[\\+-]{4,}\\d+");
    Matcher m3 = p3.matcher(str);
    
    Pattern p4 = Pattern.compile("[\\+-]{3,}(?:x|s|c)");
    Matcher m4 = p4.matcher(str);
    
    Pattern p5 = Pattern.compile("sin\\([\\+-]{2,}\\d+");
    Matcher m5 = p5.matcher(str);
    
    Pattern p6 = Pattern.compile("cos\\([\\+-]{2,}\\d+");
    Matcher m6 = p6.matcher(str);

    在初步判斷表達式的格式後,我經過+-將表達式分割爲項,以後再經過*將每一項分爲符合指導書要求的因子。以後再求導操做中,我按照指導書中的因子類型,將須要求導的因子分爲<u>常數型</u>、<u>x的冪函數型</u><u>多項式因子型</u><u>sin(factor)的冪函數型</u>、<u>cos(factor)的冪函數型</u>,併爲其創建各自的類,其中因爲sin和cos的括號內部能夠做爲一個因子,因此咱們能夠再次調用因子求導的類,判斷其中的因子是否知足格式要求並進行求導。

  • 優化

    在第三次做業中,因爲我爲了方便而在輸出的list中沒有將每項的係數和冪指數進行分開而是將每一項做爲一個係數和字符串的結合體,因此這也使我在想要進行優化時帶來了麻煩。可是考慮到本次做業除了常數項可以合併的同類項並非不少,其實在進行優化時咱們只考慮常數項的合併,並將能去掉的括號不進行輸出,也可以取得不錯的優化效果。

(2)基於度量分析程序結構

  • 整體結構介紹

    在本次做業中,面向對象的思想終於稍微出現。在做業代碼中,總共有10個類,其中除了輸入輸出、獲取因子和項以外,還創設了對於各類因子不一樣的求導類。

    可是,在本次做業中,我忘記使用繼承及接口(說到底仍是沒能理解繼承和接口的精髓),致使不少類似的類中的類似代碼屢次出現,而且沒有對於類似的類規定統一的接口。

  • 類圖

    分析類圖,能夠清晰的看出,在程序中有許多類似的類沒能進行程序代碼和接口的統一。

  • 主要度量圖

    從方法的度量表中能夠看出有關求導後結果的list建立的函數中的代碼複雜度太高,方法難以進行模塊化、難以進行測試和維護,方法的可複用性不高。這也是因爲這些方法中的循環和判斷語句使用過多形成的。除此以外,PickUpTerm類和PickUpFactor類也過於複雜,對於這些類,複雜度太高的主要緣由主要仍是運用了面向過程的方法,沒有能很好的將它們的功能進行分割。

(3)bug分析

  • 本身的bug

    在此次做業中,因爲在寫代碼時沒有可以保持一個比較清醒的態度,代碼也沒有很好的模塊化,致使有些前面考慮到的狀況在後面寫相關的代碼時忘記了。體如今代碼上即是,在進行表達式因子的讀取時,沒有考慮前面符號(其實在前面的代碼中已經對於符號進行了判斷)。因爲這一行的錯誤致使強測和互測被刀到肉疼!

    這也提醒我在寫代碼時必定先進行完備的考慮後再進行代碼編寫,而且在測試時也不能僅僅依靠現有的測試數據,要儘量尋找可能出現的錯誤,並將其進行組合。

  • 他人的bug

    因爲此次不容許wf數據的測試,讓一些同窗逃過了一劫,可是從我找到的錯誤來看,你們主要仍是格式的判斷的失誤(像我這樣因爲求導過程的錯誤實在很少/(ㄒoㄒ)/~~)。主要的錯誤有:在三角函數中沒能正確判斷因子格式、在乘法中錯誤判斷格式(主要都出如今常數項的符號判斷上)。

<u>(4)尋找他人bug的策略</u>

就着第三次做業我來談一談本身在尋找bug時的策略:

  • 總體來看,我在前兩次做業中的hack策略爲「黑盒測試」和「白盒測試」相結合:
  1. 黑盒測試:主要針對於格式的錯誤,好比wf的誤判等。可是因爲在前兩次做業中格式的要求比較簡單,因此這種測試的效率其實也不算很高,主要在因而否能構造出比詭異奇特、容易考慮不到的測試點。
  2. 白盒測試:在前兩次做業中,代碼量還算比較小,因此進行白盒測試仍是有必定的可行性的。可是要想真正完成看完每一個人的代碼仍是不現實的。因此在進行白盒測試時,我主要着眼於空格等格式的判斷以及正則表達式的構造、還有輸出時符號的判斷等。
  • 在第三次做業中,因爲代碼量的增長,而且考慮到你們求導的思路有比較類似,求導步驟出錯可能性較小,我只進行了對於格式方面的黑盒測試。運用我在寫代碼是所考慮到的特殊格式對於同組的代碼進行測試。結果顯示在第三次做業中,你們的錯誤的確集中在對於wrong format的判斷上,黑盒測試在此次hack中效果仍是不錯的。

雖然目前爲止,我經過現有的方法找到了很多bug,可是相比同組大佬仍是相差甚遠,因此我也須要在從此的debug之路上更進一步,能夠對於程序產生隨機數據上進行探索~~(雖然我以爲經過思考構造數據可能找到bug的效率更高)~~。


Applying Creational Pattern

在本次實驗中,因爲咱們的求導操做經過因子的類型區分爲不一樣的過程,可是總的來講都是在進行求導這一操做,因此咱們能夠選擇使用工廠模式

**工廠模式:**工廠模式是一種實例化對象模式,是用工廠方法代替new操做的一種模式。具體操做主要爲創建一個工廠類,對實現了同一接口的一些類進行實例的建立。

重構具體方法:

  • 首先咱們先決定將哪些類放入一個工廠中——對因子求導的類。
  • 以後先使這些類繼承一個接口。
  • 創建一個工廠,並經過判斷條件決定在工廠中調用哪個類。
  • 即可創造出咱們所須要的類。同時系統的可擴展性也大大提升。

總結

回顧完成這三次做業的過程,能夠明顯感覺到本身在這一階段的進步----從一個java小白到如今能夠較爲熟練地運用java的基本語法,而且對於面向對象編程有了初步的瞭解和實踐。可是不能否認,本身目前仍是一個小菜雞,在程序的構造和debug的能力上有着很大的欠缺,編程的思路也常常很不清晰,對java的瞭解也不深刻。

在接下來的學習中,我也須要有所針對,要不只能學其所用,更能用其所學。

相關文章
相關標籤/搜索