軟體設計之Deep Module(深模塊)

来源:https://www.cnblogs.com/hhelibeb/archive/2019/04/15/10708951.html
-Advertisement-
Play Games

類是不是越小越好?最近在讀John Ousterhout的《A Philosophy of Software Design》,感到作者文筆流暢,書中內容具有啟發性。這裡摘要一部分內容,以供參考、學習。 本文鏈接:https://www.cnblogs.com/hhelibeb/p/10708951. ...


類是不是越小越好?最近在讀John Ousterhout的《A Philosophy of Software Design》,感到作者文筆流暢,書中內容具有啟發性。這裡摘要一部分內容,以供開發相關工作中的參考、學習。

本文鏈接:https://www.cnblogs.com/hhelibeb/p/10708951.html

轉載請註明

 

在軟體複雜度的管理當中,最重要的技術之一是通過對系統的設計,使開發者任何在時候都只需要面對整個複雜度中的一小部分。這個過程被稱為模塊化設計

1,模塊化設計

在模塊設計中,軟體系統被分解為相對獨立的模塊集合。模塊的形式多種多樣,可以是類、子系統、或服務等。在理想的世界中,每個模塊都完全獨立於其它模塊:開發者在任何模塊中工作的時候,都不需要知道有關其它模塊的任何知識。在這種理想狀態下,系統複雜度取決於系統中複雜度最高的模塊。

當然,實踐與理想不同,系統模塊間總會多少有些依賴。當一個模塊變化時,其它模塊可能也需要隨之而改變。模塊化設計的目標就是最小化模塊間的依賴。

為了管理依賴,我們可以把模塊看成兩部分:介面實現

介面包含了全部的在調用該模塊時需要的信息。介面只描述模塊做什麼,但不會包含怎麼做

完成介面做出的承諾的代碼被稱為實現

在一個特定模塊內部進行工作的開發者必須知道的信息是:當前模塊的介面和實現+其它被該模塊使用的模塊的介面。他不需要理解其它模塊的實現。

在本文中,包含介面/實現的任何代碼單元,都是模塊。面向對象語言中的類是模塊,類中的方法也是模塊,非面向對象語言中的函數也是模塊。高層子系統和服務也可以被看作模塊,它們的介面也許是多種形式的,比如內核調用或HTTP請求。本文中的大部分內容針對的是類,但這些技術和理論對其它類型的模塊也有效。

好模塊的介面遠遠比實現更簡單。這樣的模塊有2個優點。首先,簡單的介面最小化了模塊施加給系統其餘部分的複雜度。其次,如果修改模塊時可以不修改它的介面,那麼其他模塊就不會被修改所影響。如果模塊的介面遠遠比實現簡單,那麼就更有可能在不改動介面的情況對模塊進行修改。

2,介面里有什麼

介面中包含2種信息:正式的和非正式的。

正式的信息在代碼中被顯式指定,程式語言可以檢查其中的部分正確性。比如,方法的簽名就是正式的信息,它包含參數的名稱和類型,返回值的類型,異常的信息。很多程式語言可以保證代碼中對方法的調用提供了與方法定義相匹配的參數值。

介面裡面也包含非正式的元素。非正式部分無法被程式語言理解或強制執行。介面的非正式部分包含一些高層行為,比如函數會根據某個參數的內容刪除具有相應名字的文件。如果某個類的使用存在某種限制,比如方法的調用需要符合特定順序,那這也屬於介面的一部分。凡是開發者在使用模塊時需要瞭解的信息,都可以算作模塊介面的一部分。介面的非正式信息只能通過註釋等方式描述,程式語言無法確保描述是完整而準確的。大部分介面的非正式信息都比正式信息要更多、更複雜。

清晰的介面定義有助於開發者瞭解在使用模塊時需要知道的信息,從而避免一些問題。

3,抽象

 抽象這一術語和模塊設計思想的關係很近。抽象是實體的簡化視圖,省略了不重要的細節。抽象很有用,它可以使對細節的思考和操縱變簡單。

在模塊化編程中,每個模塊通過介面提供其抽象。抽象代表了函數功能的簡化視圖。在函數抽象的立場上,實現的細節是不重要的,所以它們被省略了。

“不重要”這個詞很關鍵。如果沒有忽略掉不重要的細節,那麼抽象會變得複雜,會增加開發者的認知負擔;如果忽略掉了重要的細節,那麼抽象會變得錯誤,失去對實踐的指導意義。設計抽象的關鍵是理解什麼是重要的,並尋找最小化重要信息的設計。

依賴抽象來管理複雜度不是編程的專利,它遍佈在我們的日常生活中。就像車子會提供一個簡單抽象來讓我們駕駛,並不需要我們理解發動機、電池、ABS之類的東西。

4,深模塊

最好的模塊提供了強大的功能,又有著簡單的介面。術語“”可以用於描述這種模塊。為了讓深度的概念可視化,試想每個模塊由一個長方形表示,如下圖,

長方形的面積大小和模塊實現的功能多少成比例。頂部邊代表模塊的介面,邊的長度代表它的複雜度。最好的模塊是深的:他們有很多功能隱藏在簡單的介面後。深模塊是好的抽象,因為它只把自己內部的一小部分複雜度暴露給了用戶。

淺模塊的介面複雜,功能卻少,它沒有隱藏足夠的複雜度。

可以從成本與收益的角度思考模塊深度。模塊提供的收益是它的功能。模塊的成本(從系統複雜度的角度考慮)是它的介面。介面代表了模塊施加給系統其餘部分的複雜度。介面越小而簡單,它引入的複雜度就越少。好的模塊就是那些成本低收益高的模塊

某些語言中的垃圾回收(GC)是深模塊的例子之一。這個模塊沒有介面,它在需要回收無用記憶體的場景下不可見地工作。在系統中加入垃圾回收縮小了系統的總介面,因為這種做法消除了用於釋放對象的介面。垃圾回收的具體實現是相當複雜的,但這一複雜度在實際使用程式語言的時候被隱藏了。

5,淺模塊

 相對的,淺模塊就是介面相對功能而言很複雜的模塊。下麵是個可能有些極端的例子,

private void addNullValueForAttribute(String attribute) {
  data.put(attribute, null);
}

從複雜度管理的角度來看,該方法把事情變糟了。它沒有提供抽象,因為所有的功能都是在介面上可見的。思考這一介面並不會比思考它的完整實現更簡單。如果方法有合適的文檔,文檔也不會比方法的代碼具有更多信息。相比於直接操作data,它的長名字甚至會導致開發者敲擊鍵盤的次數變多。這種方法增加了複雜度(引入了一個需要開發者瞭解的新介面),但並沒有提供與之相應的收益。註意:小的模塊會更傾向於變淺。

6,Classitis

當今,深模塊的價值並沒有被廣為接受。一般常識是類需要小,而不是深。學生們被告知:類設計中最重要的事情是把大類拆分成更小的類。相似的建議還包括:“要把方法行數大於N的方法分成多個方法”,有時候N甚至可以像10這麼小。這會導致大量的淺模塊,增加系統的總複雜度。

把極端的“類應該小”是一種綜合症,可以被稱為Classitis。它源於一種錯誤思維:“類是好的,所以越多類越好”。這種思想最終會導致系統層面積累了巨大的複雜度,程式風格也會變得啰嗦。

7,例子

Java類庫可能是Classitis的最明顯例子之一。Java語言本身不需要很多小類,但Classitis文化可能已經在Java語言社區扎了根。比如,為了打開文件讀取其中的序列化對象,你必須創建多種對象:

FileInputStream fileStream =
    new FileInputStream(fileName);
BufferedInputStream bufferedStream =
    new BufferedInputStream(fileStream);
ObjectInputStream objectStream =
    new ObjectInputStream(bufferedStream);

FileInputStream對象只提供初步的I/O,它不具備緩存I/O的能力,也不能讀寫序列化對象。BufferedInputStream和ObjectInputStream分別提供了後面兩項功能。文件打開之後,fileStream和bufferedStream就沒用了,未來的操作只會用到objectStream.。

必須顯式單獨創建BufferedInputStream對象來請求緩存,這很煩人而且易出錯。如果開發者忘記創建它,就不會有緩存,而且I/O會慢。大概Java開發者會辯解說,不是所有人都需要緩存,所以它不應該包含在基本讀寫機制中。他們也許會說讓緩存獨立更好,藉此用戶可以選擇是否使用它。提供選擇空間當然很好,但介面需要設計為對常用場景儘可能簡單,幾乎所有文件I/O用戶都想使用緩存,所以就應該預設提供它。對於少數不需要的情況,庫可以提供機制以禁用。禁用緩存的機制應該明確地在介面中分離(例如,為FileInputStream提供不同的構造器,或者通過一個方法禁用/替換緩存機制),這樣大部分開發者甚至不需要意識到它的存在。

8,結論

通過將模塊的介面和實現分離,我們可以對系統的其它部分隱藏實現的複雜度。模塊的使用者只需要理解介面提供的抽象。在設計類和其它模塊時,最重要的問題是讓它們深,它們要對常見用例有足夠簡單的介面,但還是提供強大的功能。這就最大化地隱藏了複雜度。

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • table 表頭有時候需要加一些小樣式比如 必填項 這是我項目中遇到的需求 比例,產品, 部門為必填項,這個時候就需要在表頭加個紅色小星星。 首先在table中綁定:header-cell-class-name="must"事件 然後methods中寫must事件如下 must(obj) { if ...
  • 瀏覽器F5刷新的時候有一個刷新執行之前的事件,beforeunload 事件,這個事件可以提示用戶在刷新頁面之前有一個提示。 下麵是beforeunload的用法: 首先在methods中定義beforeunload事件 beforeunloadHandler(e) { // e.preventDe ...
  • 最近看了 "Dan Abramov" 的一些 "博客" ,學到了一些React的一些有趣的知識。決定結合自己的理解總結下。這些內容可能對你實際開發並沒有什麼幫助,不過這可以讓你瞭解到更多React底層實現的內容以及為什麼要怎樣實現。可以讓你跟別人有更多的談資,當然,也可以在某些場合裝一下逼。那麼接下 ...
  • 一、請求後端的JSON數據 JSON是前後端通信的交互格式,JSON(JavaScript Object Notation, JS 對象標記) 是一種輕量級的數據交換格式。 JSON是互聯網各個後臺與前代溝通必備格式,取代了原來的XML。 XML數據格式特別“噁心”,現在市場上99%以上的數據格式都 ...
  • 一、資料庫基礎 1.1什麼是資料庫? 什麼是資料庫? 答:就是一個很大的一個文件,只不過這個文件可以通過一些‘命令’操作數據; 增、刪、改、查數據; 資料庫等於持久數據和數據操作的一個統稱。 資料庫是按照數據結構來組織、存儲及管理數據的倉庫。 資料庫有哪些? MySQL、SQL server、Ora ...
  • 文章首發: "行為型模式:訪問者模式" 十一大行為型模式之十一:訪問者模式。 簡介 姓名 :訪問者模式 英文名 :Visitor Pattern 價值觀 :來訪者便是客,招待就是 個人介紹 : Represent an operation to be performed on the element ...
  • 一、簡介 ntop是一家以技術為驅動的公司,用戶多為個人和小公司,主要經營四款產品:Packet Capture、Traffic Recording、Network Probe、Traffic Analysis。 二、packet Capture 網路抓包使用具有PF_RING的商用硬體進行線速數據 ...
  • 系列鏈接地址: 深入理解設計模式 系列目錄 一、產品汪的神助攻,代碼狗的安慰劑 定義:設計模式,指的是一個場景(context)下的一種解決方法(Solution),只要大家都認可某種模式,那麼就只需要很短的一個名字,就可以代替很多很多的語言和文字交流,如果你覺得設計模式降低生產效率,那隻能說你在這 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...