1. 程式人生 > 其它 >OO unit4 summary

OO unit4 summary

Unit4

一、第四單元作業的架構設計

第四單元個人認為主要是考察對於層次結構的理解,即如何理解並處理好UML圖的樹狀結構組織,在理好層次之間以及層次內部的相互關係之後,就只剩下程式碼實現的問題了。但是不得不說,剛開始接觸UML特別是對starUML不熟悉的時候,如果指導書說的不是太清楚,真的很難動手實現,比如說在第一次作業的時候,我就完全理解錯了,導致難度飛昇,一度懷疑老師所說的“簡單”。雖然說相比JML是真的不太簡單

由於主要架構課程組都已經做好了,所以我們基本不用構思什麼架構,只需要做好層次化的組織就行了

第13次作業

這次作業只要求實現類圖相關的儲存與查詢。

在資料的儲存方面,考慮到不同層次的元素之間是有很強的關係的,常常需要進行特定的操作,比如對於class

這個元素,查詢指令中有查詢與class相關聯的需求以及查詢他所實現的介面的需求,很自然的想到被關聯的class例項和被實現的interface例項最好作為屬性放進此class例項中,當然還需要提供一系列的查詢操作。

因為查詢操作眾多,顯然需要使用hashmap進行儲存,剛好hashmap是一對一的查詢使用起來非常舒服,這裡如果出現有多個鍵相同但是值不同的話,說明存在異常(同名),再建一個name2Validhashmap,對每次查詢時輸入的鍵進行檢查是否有效就好了,速度也非常快。

但是課程組提供的介面給出的是課程組寫的類對應的例項,此時如果採用繼承來做就不太好例項化自己寫的類,因此我乾脆把課程組給的例項封進了自己寫的類中,雖然結構上有億點醜陋,有一點不OO,但是因為到了烤漆,也就將就著用了,最終形成以下結構:(其他的元素也大都如此,把課程組給的例項封進自己寫的類中,然後就能很方便地使用

public class MyClass {
    private UmlClass umlClass;
    
    private MyClass father = null;
    private MyClass topFather = null;
    private boolean updatedTopFather = false;
 	...
    private HashSet<MyInterface> interfaces = new HashSet<>();
    private String name;
    private ArrayList<MyClass> associations = new ArrayList<>();
    
    public MyClass(UmlClass umlClass) {
        this.umlClass = umlClass;
        name = umlClass.getName();
    }
    ...
    public void setTopFather(MyClass topFather) {
        this.topFather = topFather;
    }
    
    public MyClass getTopFather() {
        return topFather;
    }
    
    public void setUpdatedTopFather(boolean updatedTopFather) {
        this.updatedTopFather = updatedTopFather;
    }
    
    public boolean hasUpdatedTopFather() {
        return updatedTopFather;
    }
    ...
    
    public void addOperation(MyOperation operation) {
        operations.add(operation);
    }
    
    public HashSet<MyInterface> getInterfaces() {
        return interfaces;
    }
    ...
}

此外,由於第一次作業CPU使用時間限制為2s,其中有幾個非常耗時的查詢操作,查實現的介面,(這裡還需要查介面的繼承情況),查關聯的類等。

考慮到實現的難度,我選擇用遞迴來解決問題,同時採用記憶化加速。即將相關的操作提供一個flag,如果flag有效則直接返回對應的查詢元素,若無效,則進行對應的遞迴查詢,並更新相應的資訊的儲存。

異常處理方面,要特別注意異常丟擲的順序,大體按照從頂層向底層的順序拋異常就好了。

最後,考慮到輸入元素的順序可能不確定,因此我選擇把所有輸入的元素先分類儲存,然後按照合理的順序一個一個地存進相應的類中,為了方便管理,我寫了一個MyinfoLoader的類來專門處理讀入資訊的問題。

第14次作業

第二次作業相比第一次多了時序圖和狀態圖的處理,處理過程完全一樣,有了第一次的經驗,這次作業做起來顯得比較簡單。同時CPU使用時間放寬到10s,再加上多的兩個UML圖的查詢基本上沒有什麼耗時的查詢操作,完全不需要什麼演算法,直接用暴力做法硬莽就是了。

由於新增了兩種UML圖,我新增加了兩個模組進行管理:

第15次作業

這次作業需要增加Rule的check操作,一共八條,可能是因為在烤漆,整體實現難度不太高

Rule3Rule4要求介面不能重複繼承介面,類不能重複繼承類,類不能重複實現介面。

由於在我的架構中,MyinfoLoader在讀取資訊的時候需要將實現的類或者繼承的類(介面)存進屬性,只需要對於第一次作業資訊讀取儲存的部分加一個判斷,並提供一個flag,如果儲存資訊的過程中出現了不合法的行為,那就直接把對應的flag置為有效,檢查的時候查對應的flag就行了

比如在Rule4的檢查中:

如果沒有update並且父類不為空,這時候更新他的繼承的介面首先需要遞迴地更新他父類的介面,然後檢查一下父類是否合法(如果父類標誌位有效,子類置標誌位)

再對父類實現的介面做一遍更新,同時如果介面標誌位有效(不合法)那子類肯定不合法,置標誌位。

最後把所有的介面合在一起去重,看是否有重複的,如果有表明需要置標誌位,無效。

check模組中只需要對每個類更新一下,然後查一下標誌位就好了:

public void checkForUml003() throws UmlRule003Exception {
        HashMap<String,MyInterface> id2Interface = myUmlClassModelInteraction.getId2Interface();
        Iterator iterator = id2Interface.entrySet().iterator();
        while (iterator.hasNext()) {
            Map.Entry<String,MyInterface> entry = (Map.Entry)iterator.next();
            MyInterface myInterface = entry.getValue();
            myUmlClassModelInteraction.updateFatherInterface(myInterface);
        }
        iterator = id2Interface.entrySet().iterator();
        HashSet<UmlInterface> ans = new HashSet<>();
        while (iterator.hasNext()) {
            Map.Entry<String,MyInterface> entry = (Map.Entry)iterator.next();
            MyInterface myInterface = entry.getValue();
            if (myInterface.getDup() == true) {
                ans.add(myInterface.getUmlInterface());
            }
        }
        if (!ans.isEmpty()) {
            throw new UmlRule003Exception(ans);
        }
    }

Rule2 有裡面關於類和介面是否成環的問題,因為CPU時間十分充裕,直接用暴力做法就好,需要注意的是,對於已經遍歷過的點需要打上標記,否則將導致TLE

關於類的成環問題,由於只存在單繼承,最簡單的做法就是一直查父類,看是否能回到開始的類,如果能,說明類的繼承會成環

需要注意的是,當所查的類在一個環之外的時候,會出現死迴圈,所以還得記錄查詢路徑,當再次出現記錄的路徑裡的類的時候應該結束查詢。

介面成環我採用了bfs如果會回到最初的介面表示成環,注意為查過的點打上flag

二、四個單元中架構設計以及OO方法的演進

  • 第一單元:主要是多項式求導的相關問題,重點在於理解類的繼承以及對於面向物件思維的初步理解,由於剛開始基本沒有面向物件的思維,做出來的架構很差,重構一次之後用二叉樹做出了自認為擴充套件性很好很棒的架構,但是一到化簡就頭皮發麻了,之後聽到老師說不一定是二叉樹,可以是多叉樹(其實我感覺二叉樹相比多叉樹更具有面向物件味),然後又做了一次重構,達到了比較好的效果。我的基本架構就是不同的函式雖然求導的具體做法不同,但是都可以抽象為項,然後項和多項式之間可以相互套娃,都有求導介面,對頂層求導,會將求導這個方法一層層分發下去,而底層有不同的具體實現。
  • 第二單元: 主要是關於多執行緒的理解,關於多執行緒程式碼的編寫與除錯,關於生產者消費者以及其他部分設計模式的理解。在第一次寫的時候由於沒有考慮清楚細節,對於死鎖的認識也不清晰,遇到了各種各樣的bug,一團亂麻,再加上對於多執行緒debug也不熟悉,乾脆推了重寫,由於第一次作業架構還可以,後兩次作業就直接把前面的架構包一下就能直接用了。總的來說就是需要分層次,該電梯管的就電梯管,該排程器管的就排程器管,不要有“長臂現象”,否則容易造成死鎖,並且效率損失嚴重!
  • 第三單元:主要是關於JML語言的理解與實現,把規格這個概念建立在我們腦海中。雖然寫起來一長串一長串的(課程組寫ಥ_ಥ )但是對於理解確實很友好,不會產生二義性。本單元是真的可以說沒有任何架構,把指導書看好然後對著課程組的程式碼實現相關的函式就完事了,唯一需要注意的就是方法的複雜的,所以會涉及到一些演算法的問題。
  • 第四單元:主要是關於UML圖的理解,訓練的是層次化模組化的能力。首先需要通過starUML理解好作業中的UML圖(類圖,時序圖,狀態圖)的相關概念與樹狀結構,然後自己構造相應的類提供相應的儲存與查詢方法進行查詢。相比第三單元多了些架構設計,但沒有多很多,做好層次化管理就好。

三、四個單元中測試理解

  • 第一單元:第一次自己動手寫評測機,對於個方面都不太熟悉,加上第一單元我並不是很會遞迴下降,不僅作業中讀取很費力,評測機的資料生成也很費力,即使勉勉強強生成了資料強度也還是不高,導致第一單元作業中有很多bug淚目,具體來說我的做法就是通過正則表示式解析逆向生成資料,然後跑出結果,然後與正確結果對拍,正確結果來自Python裡的sympy……掌握了評測機的主要搭建思路:

    (構造資料->用命令列跑程式碼並記錄結果->與其他結果對拍並記錄對拍結果)為後面的評測機書寫打好了基礎。

  • 第二單元:在Python中構造電梯類,生成資料之後,跑程式碼,每輸出一個提示資訊,就讀取並解析,更新Python中電梯類的相關狀態並檢查,一旦不合規範就相應的錯誤

  • 第三單元:隨機生成各種資料(強度可能不高,用數量保證質量),然後找幾個同學一起跑並對拍;專門構造一些容易超時的針對性資料,用time庫來測執行時間,精度很高

  • 第四單元:先自己構造各種邊界資料,考慮到一些基本情況,進行手動人工測試,確保程式大致正確。然後手工生成針對性資料,多個同學一起跑並對拍。

四、課程收穫

一學期的OO課終於結束啦!總結了一下,大概有一下收穫:

  • 面向物件思想的初步建立,無論什麼好思想都是深邃的,思想的建立不可能一蹴而就,面向物件程式設計思想的初步建立將自己領進了這個領域的大門,為之後自己的探索指了一條明路
  • 碼量的飛躍,一學期算下來作業(含重構)加評測機大概也有6000~7000行了吧
  • Java語言的熟悉,想要熟練掌握一門語言最好的方式就是多用它編寫程式碼。此外踩了許多奇怪的坑,積累了經驗
  • 評測機編寫能力大大提升
  • 學會了許多工具的使用,特別是git,對於碼量較大的專案是必不可少的東西,以及IDEA裡各種大幅提升體驗的外掛
  • 瞭解並掌握了相關的設計模式
  • 建立了相關概念,例如:多執行緒,JML,UML
  • 磨礪了心智

五、具體改進建議

  • 實驗課最好能公佈答案,不然自己根本不知道做對沒,上機幾乎等於無效上機,實在想不到不公佈答案的理由
  • 指導書中某些寫的不清楚的地方希望能寫的更清楚一點,特別是第四單元,看完指導書真的是一頭霧水
  • 希望在每個單元結束後能展示一部分優秀程式碼,因為真的覺得自己有的地方寫得很醜陋
  • 希望在互測中刀人之後能刀中了誰的反饋,這樣就不會有漏網之魚了,同時也能減少惡意Hack的情況
  • 希望研討課的質量能更高一些,最好定幾個ddl,做完PPT後助教要進行稽核,對於質量不合格的打回重做,仍舊不合格將取消本次研討分享資格
  • 討論開通搜尋功能,並開通標記功能(對於有的帖子以及看過了,可以標記為看過,避免浪費時間)