1. 程式人生 > >面向對象-第一單元總結

面向對象-第一單元總結

輸入格式 優化 ret 工廠 出了 環復雜度 idt 體會 -s

一、對面向對象的理解

  有位同學給java的面向對象做了一個形象生動的類比,我覺得很有道理,大概按我的理解如下:

技術分享圖片

    • 結構的形成
      看圖之前,我們要先明白,世界上是先有了實體,才有了一步步抽象至以上的體系結構,當然也未必是自底向上逐步抽象,也許在最初的認識體系中,只有故宮裏的植物C、植物、和存在,或許迎客松A和蒹葭B都是植物的對象,在之後的認識中逐步向上抽象出生物,向下細分為樹和草等等。
      但無論如何,所有的抽象類都是我們從實體中歸納總結出的,不是憑空產生的。   
      在真實的程序設計中或許我們也是如此,也即先有簡單的層次,生物-植物-ABC,隨後逐步細化功能叠代開發。
    • 類與接口

      抽象類與接口十分相像,一般用借口能實現的東西我們都可以通過抽象類來實現,但從結構上看來,抽象類是分類,接口是功能,就像圖中的光合作用是接口,樹和草是類,樹和草描述的是實體的構成模式,光合作用描述的是他們所具有的功能,還是有很大區別的。

    • 抽象類
      抽象類並不是不可以指代一個對象,僅僅是不能實例化一個對象,實例化的對象可以通過抽象類來指代,就像故宮裏的那顆植物可能是一棵樹,但是同樣可以通過植物來指代。

二、實踐與設計思路

  至今為止面向對象開課以來已歷五周,共實現了三次作業,都是表達式求導,功能逐步增加,對於面向對象理解的逐步加深也對我的程序結構產生了不同的影響,以下作出歸納:

  

  • HomeWork1

  題目描述:多項式求導,多項式僅由帶符號整數、x的一次函數與x的冪函數構成。

  對於面向對象一知半解,以為一個類用於當作函數主路口,另一個類用於實現功能就已經半只腳踩入面向對象的大門了;實際上不過是“include”一個頭文件的過程式設計而已。當然功能實現沒有問題,只不過到了HomeWork2需要重寫了。且結構上維護困難。

技術分享圖片

  由於Derivation類僅僅實現函數的入口功能,連格式判斷都放在Poltnomia類中,所以直接的結果就是該類的體量巨大,度量數據超標都是此類的問題。

  另一方面,由於正則表達式判斷時(getIn方法)使用的是多個if-else-return結構,結構化程度ev(G)與循環復雜度v(G)都很大。但調試與理解起來並不是很令人費解,當然這是個人非數據的感覺。

  總而言之,第一次作業的實現並沒有明白面向對象程序的編寫方式,用完全過程式的思想去編寫程序,唯一覺的有利於編程的是java巨大方便的類庫~

  • HomeWork2

  題目描述:多項式求導,多項式由帶符號整數、x的一次函數、x的冪函數與x的sin、cos函數構成。

  題目一出來,就發現第一次的作業白寫了,於是有感為了讓第三次的作業好寫一些,盡力的修修補補得到了如下的結構。因為寫的時候並沒有題頭的所述的那般理解清楚,所以很多結構上有冗余,第一次使用繼承、抽象類,還沒有很深的理解,於是勉強有如下的結構,但自認為結構上或不甚清晰,類內部的實現有些混亂。主要體現在AddFunction和MultyFunction的組成,使用了Function的Array組成其數據結構,但一方面這debug不方便,另一方面優化時不容易

技術分享圖片

  首先從類圖看,Term是函數入口,Function作為求導函數的頂層抽象類,直接繼承它的是加和函數、乘積函數和基本函數,基本函數也是抽象類,其有冪函數、X函數、常數函數和sin、cos函數五個子類。從結構實現上,基本實現了我所預想的結構。但靜態分析仍有問題。

技術分享圖片

  如上圖,由於方法過長,右邊的方法僅給出了超標部分的截圖。

  從類的結構來看,Term和Function的平均復雜度很高,這是由於Term沿用了正則表達式判斷輸入格式的方法,仍然是if-else-return加大了復雜度,Function是因為兼具了工廠函數的功能,並不僅僅作為抽象類而存在,我想這應該需要避免,功能和數據結構的定義最好分開。

  從方法復雜度看兩個match方法都是使用了正則表達式if-else-return的結構,加大了復雜度。而Multy中的getout主要原因是用多個if結構來優化造成的結果。技術分享圖片

  類間的相互依賴關系如上,因為MultyFunction和AddFunction中的函數項組成采用了頂層抽象類型,即內部類型結構表述與思考有些混亂,為了避免出現錯誤,就使用了最大的描述類型。這點在第三次作業做了些改變。

  • HomeWork3

  題目描述:多項式求導,多項式由帶符號整數、x的一次函數、x的冪函數與x的sin、cos函數構成,允許sin、cos內部嵌套表達式及其他函數,允許冪函數底數使用x的函數項或表達式。

  由於第二次作業的正確決策,第三次就不需要重新考慮結構,僅僅調整了冪函數的位置,並對結構內部進行了一些修改與優化,包括精確化函數類型,加和函數明確為乘積函數組成,乘積函數明確為冪函數組成,考慮嵌套,冪函數、三角函數內部使用加和函數類型。正則表達式判斷格式直接使用了第二次的代碼,基本沒什麽修改。另一方面,分離了工廠函數和頂層抽象類,使得結構更加清晰。

技術分享圖片

  類圖結構上並未有太大變化,入口函數在Derive類。

技術分享圖片

  Derive類中包含了match正則表達式匹配方法,if-else-return結構使復雜度增大。當然,關於這個問題,可以通過遞歸分部解決,在遞歸部分我也加入了判斷,或許程序中有冗余,但是並沒有太在意去改變。CreatFunction類是生成函數,因為需要括號匹配,這一點或許可以通過遞歸逐層解決,但是在這次作業中,我使用的是過程式匹配,這或許有違面向對象的初衷。

  由於結構的更改,Power作為優化中極為重要的一步,通過if來進行判斷。復雜度略有增加。

  另一方面,因為一開始寫的時候並沒有了解到instanceof可以判斷函數具體到那個子類。所以有isBaseOr。。。來判斷嵌套函數是否是常數函數或者表達式函數。

 技術分享圖片

  通過清晰化結構一定程度降低了類間的依賴度。

  • 總結

  三次作業的第一次作業完全按面向過程式編程,維護程度比較低下,程序測試分數也較低。第二次作業,第一次用了面向對象的思路編寫程序,雖然測試分數更低了。。。當然或許第一次作業沒有為第二次作業留下出了bug數據以為的好處。第三次作業很大程度上復用了第二次作業的代碼,得到了不錯的成績,也算是一種鼓勵吧~體會到了復用的好處。

三、bug分析

  • 第一、二次作業
  1. 公測

  2. 互測
      關於前兩次互測,被發現的bug都是FormatWrong,正則表達式考慮不完全所造成的後果……因為通過正則表達式判別,或許與設計結構關聯不大,一二次的結果相似。
  3. hack策略
      通過自己程序的bug和復用曾經自己被hack的bug來測試別人的bug。效果不錯。
    也有可能是因為身處C組的緣故。
      查看別人的源代碼,有針對的hack,成功率很高,但是效率比較低,看別人代碼大多數時候真的很累。
  • 第三次作業
  1. 公測

  2. 互測
      因為不測WrongFormat!!!(如果測可能還是有問題)所以被hack的主要內容是關於常數項的判斷,與前兩次類似的地方在於,都出現在方法復雜度高的地方。
  3. hack策略
      通過自己程序的bug和復用曾經自己被hack的bug來測試別人的bug。
      查看別人的源代碼,有針對的hack,未成功過。。。或許是水平不夠。

四、總結與Applying Creational Pattern

  大概收獲最大的並不是某次作業,而是最後的一次同學分享。就如題頭說的,面向對象的建構不是一蹴而就的,或許我們最先反應過來的模型都是簡單的相對不抽象也不細化,得到的體系與結構也僅僅是不完善的。

  表達式求導,在第二次采用面向對象方法設計的時候,確實在碼代碼之前進行了深入的思考,想清楚得得到一個清晰的架構,最後的結果是得到了一個初步的模型,但對於內部細節並沒有很完善,具體的分析前文提到了。通過反思與和同學的交流,在第三次作業重寫了部分方法,重新整理了數據結構,相對的跟清晰的獲得了體系。當然任然存在在不完善的地方,通過反思與思考仍然可以更進一步的優化~

面向對象-第一單元總結