軟體構造課堂筆記(1)重新理解軟體結構

2021-10-05 02:31:41 字數 2714 閱讀 8511

有待解決的問題

隨著課程進度推進,我們需要處理的軟體結構也變得更加複雜。課上在演示結構關係時,習慣將委託、繼承、實現等這些物件關係畫在乙個類圖里,可能理解起來還會比較讓人困惑。

這裡我想轉換一下看待軟體結構的視角,將這種錯綜複雜的關係圖分解為2棵不太嚴格的樹,重新理解軟體的結構。這兩個模型只是我個人理解所使用的,並不是書面上標準的概念。

接下來,我們主要將視角集中在類、物件的層面,著重於委託和繼承關係,構建這個模型;

我們復用類的方法,主要分為委託(delegation)和繼承(extends)。

委託主要就是在自己的方法中,使用定義在其他類裡的方法。換種說法,就是將自己的一部分功能分離出去,交給其他的類來完成。

而繼承則是將父類的屬性和方法都繼承下來,並且可以進行一些自我的定製,在父類的基礎上新增新的要素或者修改原有屬性、方法。另外還有一種特殊的繼承關係,就是對介面的實現(implements),我們接下來也將實現當成繼承的一種進行論述。

構建模型之前,不妨先從乙個比喻開始說起。

從委託和繼承的含義上不難想象,我們可以把乙個程式中的所有物件、類、介面,當成乙個社會的公民,而程式就是這個社會。

委託關係對應著僱傭關係,繼承關係對應著家庭關係。

僱傭關係支援著整個社會的運作,是社會功能產出的主體。而家庭關係主要功能並不是直接地給社會做貢獻,它只是在不斷地產出人力資源,加入社會僱傭關係網,支援社會運作。

通常而言,好的僱傭關係和家庭關係都有著一定層次結構。在僱傭關係的方面,越上層的「物件」可以排程越廣泛的資源。

模擬僱傭關係,我們就可以基於委託關係構建出乙個樹型的結構,最上層的是面向客戶的api,接下來的是它所委託的各種物件。這個結構中,是以物件作為結點的,其中的介面畫成乙個大括號,留出空位給實現類結點,表示介面沒有實際的**實現,需要用介面的實現類來填充。

繼承關係也可以模擬家庭關係。以object類為根,我們也可以構建起乙個繼承關係樹。但這個樹不嚴格,而且是倒過來的,之所以這麼設計是為了和委託關係樹相對應。

一般來說,在繼承關係樹中越上層的類,越抽象,實際功能越少,在委託關係樹中往往越接近底層,甚至不會在委託關係中作為物件使用。比如繼承關係樹中還有一些介面,專門開空頭支票(spec),給後代挖坑;抽象模擬介面要好一點,還能實現一些功能,只是也會留一些坑給後代填。而我們在委託關係樹中,使用的一般都是繼承關係樹中的葉節點類例項化的物件。

介面和比較抽象的類(不是指抽象類,是指在繼承關係中較上層的類)在委託關係樹中主要用於作為物件引用型別,這就能告訴委託方,委託物件「身出何處,師出何門」,所以委託方就可以拿它祖輩的規格要求它,正如前文所述,這兩種概念在委託關係樹中作為引用型別使用時,用乙個大括號表示。抽象類則很少在委託關係中使用,就暫時不在委託關係樹中引入符號。

以上所構建的兩個「樹」模型並不是嚴格意義上的樹,實際應用時,委託關係往往更加複雜,層次未必有樹這麼分明,最終可能還是會設計成乙個圖;繼承關係中廣泛地使用介面,這將導致乙個結點有多個父親,無法稱之為樹。但是接下來我想說明的是,乙個設計良好的軟體結構,「繼承關係」結構暫且不論,其「委託關係」的結構應該是盡可能接近樹形結構的。

怎麼樣可以設計出好的軟體結構呢?

建立好這兩種模型,原來錯綜複雜的類圖就可以分解為這兩種檢視來分析。以此可以更清晰地設計軟體。

我們在設計乙個程式時,實際上就是在構建委託關係樹,並在不同的層面、不同的物件之間進行切換。在委託關係樹中,接受需求後,分而治之,先從上層開始設計spec,不斷利用委託分解我們的需求,直到分解任務的代價比直接寫**的代價還要高時,就可以從底層開始往上設計了。

從上往下分解時要注意保持清晰的層次結構,保證明確的分工,盡量使依賴關係侷限於同乙個層次的其他物件或者直接委託關係物件之間,保證低耦合度。

從下往上實現時,注意進行增量式的迭代過程,以測試驅動開發保證子模組的正確性,同時盡可能對上層隱藏內部細節,為可能的後期調整做準備。

按照樹形結構設計,就可以有條理地完成以上這些設計。

那麼繼承關係在這裡扮演什麼角色呢,如果說委託關係樹是我們構建物件,那麼繼承關係樹(一般不嚴格)則是我們的工具框架,也可以模擬成遊戲中的「技能樹「。如果有一類物件具有極大的相似性,同時十分易於由共性對應的類延伸擴充套件而得,我們就可以用繼承關係來組織並建立這些「工具」(類)。

對於面向可復用的程式設計,大致可以有以下兩種思路。(待補充,其實還是繼承和委託)

在抽象關係樹中構建出合適工具框架,在不同的應用當中可以通過繼承的方式拓展和調整原有功能。定製程度高,更加靈活,但是需要對父類有全面的了解,同時由於缺少了層次結構,融合程度高,不易修改。

在抽象關係中定義完工具之後,僅關注工具類的api,通過委託工具類例項的方式在不同的應用裡使用工具類。工具僅僅暴露api,因此更易於使用,同時具有層次結構,易於替換工具類的具體實現。

以上兩種思路也可以配合起來使用。

如何有效地調整委託關係的結構,使得結構趨於樹形結構;

如何表示委託和繼承結合在一起的複雜結構;

目前為止,以上的構建都基本還停留在編碼階段。工具類(繼承關係樹)確實在編碼階段就固定下來了,但」委託關係「在執行階段卻會隨時間不斷發生變化。所以我們還需要考慮委託關係在執行階段如何動態地構建。

考慮介面、泛型在構建過程中可以扮演的角色,整個構建過程還可以變得更加靈活。

軟體構造 課堂筆記3

本文內容主要基於老師上課的內容,以及上課的ppt 類 靜態的 物件 執行時存在的動態的 上圖是基於時間的計費系統 例,乙個程式,程式中的所有物件通過名為id的成員變數來儲存唯一的id,如何管理id?一種比較好的實踐方式是,將id的建立全部放在newid 函式中,這樣只需要呼叫newid 函式,而不需...

軟體構造筆記1

第一章 第一章的重點是軟體構造的多維檢視,總共有三個維度 所以這三個維度可以劃分為八種型別 1 build time moment code level 是基於詞彙的半結構化源 半結構化是指近乎自然語言的風格 遵循特定的程式設計語法,前者方便程式設計師,後者方便編譯器。語法層面指面向語法的程式結構,...

課堂筆記1

原碼,反碼,補碼 原碼,反碼,補碼是機器儲存乙個具體數字的編碼方式 8位二進位制位中 第一位表示符號位,其餘位是編碼位 原碼 資料的二進位制表達形式。反碼 正數的反碼不變,負數的反碼在原碼的基礎上除了符號位,其他都取反。補碼 正數的補碼不變,負數的補碼在原碼的基礎上除了符號位取反,並且在最後位上加一...