1. 程式人生 > 其它 >關於第四單元與整個OO課程的總結與反思 - Coekjan

關於第四單元與整個OO課程的總結與反思 - Coekjan

Unit4架構設計

第一次作業

本次架構極差, 幾乎將所有邏輯都塞在了 UmlInteraction 中, 談不上設計.

若要找某一具有 id 元素的父元素, 則簡單粗暴地採用 idMapElement.get(idMapElement.get(id).getParentId()) . 不具有層次關係.

第二, 三次作業(重構)

這兩次作業中, 我將上述對映化為具體的類成員, 將官方包中的類封裝為功能更強大的類.

抽象泛型類 UmlElementInfo 用於方便後續的封裝:

/* package */ abstract class UmlElementInfo<T extends UmlElement> {
    /* package */ static final Map<String, UmlElementInfo<?>> ID_MEMORY = new HashMap<>();

    private final T element;

    protected UmlElementInfo(T element) {
        this.element = element;
        ID_MEMORY.put(element.getId(), this);
    }

    /* package */ T getElement() {
        return element;
    }

    public String getName() {
        return element.getName();
    }

    public UmlElementInfo<?> getParent() {
        return ID_MEMORY.get(element.getParentId());
    }

    @Override
    public boolean equals(Object obj) {
        return obj instanceof UmlElementInfo &&
            Objects.equals(((UmlElementInfo<?>) obj).element, element);
    }

    @Override
    public int hashCode() {
        return element.hashCode();
    }
}

IDEA 生成的圖還挺酷的. 但是圖片太大了, 可能需要載入一段時間.

可以看到大量中間圈中就是包裝類(均繼承該抽象泛型類)和相關的依賴.

通過這個封裝, 基本上就解決了複雜的變換與資料儲存問題, 在第二第三次作業中基本上不需要做任何改動.

四個單元中的架構設計與面向物件方法理解的演進

整個課程體驗的過程中, 我並沒有刻意去套用某種架構設計去完成某些具體任務, 而是通過解讀需求來決定架構的設計.

第一單元 - 對抗任務複雜度與提取任務共性

第一單元的最重要的任務就是建立起函式儲存模型, 要求其能夠經受起增加函式型別的迭代考驗. 那麼就需要設計一個通用的函式類模型 - 抽象 Function

- 用於承載具體的函式類, 並賦予其一些通用職責: 作為一個成熟的無窮次可微函式, 你應該會自己求導和字串化了!

這樣的職責設定, 相當於一種規範, 使得符合這樣規範的函式類都能夠融合到已有的函式類家族中, 而不引起任何的體系改動.

這樣提取任務的共性, 就能夠對抗任意增加函式型別的複雜任務.

第二單元 - 對抗執行緒安全問題與複雜的電梯模式

第二單元的最重要的任務就是建立起執行緒安全控制, 要求其能夠經受起增加電梯種類與數量, 模擬情景變化的迭代考驗. 那麼就需要設計執行緒安全類, 來進行協調多個執行緒對共享資源的互斥訪問.

可以說, 只要設計好了執行緒安全類, 就已經完成了大部分難點與避免了大部分bug了.

本單元的另一重要任務是電梯狀態變化的描述(但其實這部分不採用具有擴充套件性的寫法也能夠平穩通過第二單元), 筆者採用了狀態模式來建模電梯的狀態變化, 只要設定好當前狀態的直接後繼狀態, 即可確保狀態變化的正確性.

此外, 還有一個重要的任務是電梯執行策略的描述, 筆者採用策略模式來建模電梯的執行策略, 只要給出電梯的當前執行狀態與外來的需求, 即可進行電梯的執行決策. 只要保證策略類的邏輯正確, 即可保證外來需求完全解決.

第三單元與第四單元 - 對抗多類大量資料的通用性儲存

這兩個單元有一個共性的重點問題是建立起儲存大量資料的通用性儲存容器, 如一對多封裝 Map<T, Collection<U>> 這部分的難度並不大, 只要對手造輪子進行鍼對性的單元測試, 就不會出什麼問題.

四個單元中測試理解與實踐的演進

四個單元中, 僅有第二單元沒有搭建資料生成與評測(或對拍)機.

  1. 第一單元: 基於形式化文法的資料生成機與基於sympy黃金模型的正確性評定機.
  2. 第二單元: 白盒測試(俗稱肉眼盯程式碼), 找出執行緒安全問題, 並通過一些極端手造樣例來輔助驗證.
  3. 第三單元: 基於指令格式的資料生成機與基於本地標程的正確性評定機.
  4. 第四單元: 基於指令格式的資料生成機與對拍機.(中途咕咕)

總的而言, 由於前三單元的資料與資料之間的關聯可以很弱, 所以測試難度在前三個單元都不高; 到了第四單元, 我發現UML類圖元素的生成與組織還是相當困難的, 很難才能做出合格的資料生成機, 因此第四單元的後兩次作業也就沒法向後迭代資料生成機了.

關於第四單元的資料生成, 筆者反思, 或許需要依賴面向物件的構造思路, 才能更好地管理資料生成邏輯, 控制工程複雜度.

課程收穫

所學

總體而言, 我在OO課程中, 尤其是課程作業中學到了很多東西.

  1. Java語言及其高階特性
    • 泛型程式設計
    • 流式程式設計(函式式介面)
    • ...
  2. 面向物件理念與設計方法論
    • SOLID
    • 各類模式: 狀態, 策略, 單例, 工廠, 抽象工廠, 命令, 生產者消費者, 讀者寫者...
    • ...

所想

北航第一屆學生入學時, 有橫幅"歡迎未來的紅色工程師"; 計算機學院的英文全稱是 School of Computer Science and Engineering (電腦科學與工程學院); 高院長上學期授計算機組成原理課時反覆強調工程化方法; OS課要求同學們閱讀大量工程化程式碼; OO課要求同學們學習運用面向物件的思維方法來對抗工程複雜性, 獨立完成魯棒, 可擴充套件, 可維護的軟體程式. 可見資訊化語境下對工程化的強烈需求.

在整個OO課程的緊湊節奏下, 筆者也不斷錘鍊自己的工程化能力, 在寫下每一句程式碼時都仔細振作其魯棒性, 可擴充套件性, 可維護性. 總體看下來, 筆者順利完成了每一次作業, 最終保持住了強測互測不被hack的記錄, 這可以看作是對筆者工程化能力的肯定.

願筆者與諸君都能在今後的工程生涯中都能堅持工程化思維, 編寫出健壯的工程產品, 不負資訊時代給我們資訊科技學生的使命.

關於課程的改進建議

歡迎讀者一起探討下述有關本課程的改進建議.

預習部分

有一點大刀闊斧的感覺.

將每個同學的程式碼公開, 不進行查重或只進行弱查重:

  1. 高層次同學往往在預習部分就展露鋒芒, 將他們的程式碼公開, 有利於中低層次同學的學習與研究.
  2. 同學們可以互相找bug, 互相提出修改意見, 促進"教中學".

研討課

從題目閱讀到程式碼實現, 這是一個很複雜的過程, 希望今後的研討課可以多多涉及這方面的內容, 如將這部分內容設定為必做或推薦選項. 讓優秀的設計實現思路充分展現, 讓大家都能領會一個專案的誕生全過程.

交叉驗題

面試中學來的專業詞彙 hhh

加強交叉驗題水平, 驗證題目表述的精確性, 保證測試資料合乎題目要求.

互測部分的改進

併發互測

希望能夠加入併發互測選項, 如同時併發100個程序, 可能更能測試出java的併發bug.

迭代展示

在一個單元內, 假設參與第 \(n\) 次互測的同學有 \(\{P_1, P_2, \dotsm, P_k\}\) , 則 \(\forall i\in[1,k]\) , \(P_i\) 能夠在第 \(n+1\) 次公測結束後拉取其他同學在第 \(n+1\) 次作業中最後一次提交的迭代進度與具體內容, 以及同一單元內前幾次作業中最後一次提交內容.

這樣做的好處是, 如果某同學認為同屋者的程式碼水平優秀, 那麼就可以跟蹤其迭代軌跡, 學習其迭代的藝術, 增長自己的能力.


6系的金課讓我永生難忘, 衷心祝願OO課發展得越來越好!