Try   HackMD

物件導向 個人心得(2

不知自己不知道, 那你會以為你知道.

tags: OOP 個人心得

在 2018 年左右建立的觀念(參考此篇

前言

    主要記錄從 2018~2021 三年來關於物件導向的觀念上是否有什麼改變, 所以想在補充一點資訊後產生此篇.

此篇參考的資訊:

程式如何正確撰寫 ? | 物件導向程式設計 - SOLID 設計原則 : SRP、OCP、LSP、ISP、DIP

Laravel、Ruby on Rails、Django 使用 Active Record Pattern 框架的最大問題:到底該把 save 寫在哪裡?

OOP 程式開發:用一個簡單的數學公式來幫忙設計類別

元件如何正確使用 ? | 元件耦合性三大原則 : ADP、SDP、SAP

運算思維的核心 - 抽象化


「用一個簡單的數學公式來幫忙設計類別」

  • 解決 God Object 上帝物件
    • 把相關的 property 跟 method 抽出來, 很輕易就能拆出多個 CR 更高的類別.
    • 當你這麼做的同時通常很神奇地,類別命名會自然浮現.
  • Long Method 過長的解決方法, 可分兩步驟改寫(前提: 只在職責較為清晰的類別用以下步驟, 因職責不明確的類別通常是 God Object 若用以下步驟抽為屬性時, 通常會難以辨識屬性的定位, 更多的是模糊關注點.)
    • 步驟一
      • 先把每段任務拆成各自的多個小 method, 把用到的變數傳進去
      • 你會發現同樣的好幾組變數, 反覆傳到好幾個 method, 似乎變得更糟糕了
    • 步驟二
      • 這些反覆傳送的參數, 變成類別的 property
      • 你會發現很多 method 不再依靠參數, 而是轉跟 property 互動
      • 因這些 property 反覆在多個 method 被使用, 這時 CR 也跟著提高了
  • 內聚係數 (Cohesion Ratio) CR 越高越好: (每個方法用到的屬性數量加總)/(屬性的數量 * 方法的數量)

SOLID 設計原則 : SRP、OCP、LSP、ISP、DIP

  • SRP
    • 一個模組應該只對唯一的一個角色負責
    • 單一職責實際上是一種「分類」的方法,依據的是「不同角色的使用者」、「以不同視角的觀察」。
  • OCP
    • 一樓已經完成, 若需追加新的設計只能從二樓開始
    • 不應再為了某種需求在一樓的牆壁鑽孔、打洞
    • 萬一剛好是某個重要結構,可能導致傾斜或倒塌,這樣肯定得不償失
  • LSP(要有繼承關係)
    • 若對於型態 S 每個物件 o1 都存在一個型態為 T 的物件 o2
    • 使得在所有針對 T 編寫的程式 P 中, 用 o1 替代 o2 後, 程式 P 的行為功能不變, 則 S 是 T 的子型態
    • 上述簡而化之就是,子類別能替代父類別。如果發現子類時常覆寫父類方法,或是父類的方法改成可覆寫。就要注意子類別是否分類錯誤,或者父類別定義模糊 等因素導致。
  • ISP
    • 不應強迫客戶端依賴它不使用的方法
  • DIP
    • 高層次的模組不應該依賴於低層次的模組, 兩者都應該依賴於抽象介面

還有「元件的內聚性原則」與「元件間的耦合性原則」

  • SDP 穩定依賴原則 (stable dependences principle)

    • 穩定的元件 ?

      • 本身元件的類別被外部元件或功能所依賴
      • 本身元件中的類別不依賴外部元件或功能的類別
      • 不容易被依賴於自身的外部元件或功能給影響
      • 因需求變動或新增時, 進而影響依賴的外部元件或功能
    • 不穩定的元件 ?

      • 本身元件沒有被外部元件或功能依賴, 但依賴了很多外部的元件
      • 外部的元件更動, 都有可能受到影響本身元件
      • 但本身元件的改動, 卻不會影響到其他元件
      • 修改該元件的主因, 都因其它元件修改時才改動
    • 穩定度計算公式 => 不穩定性 I (instablility) = FanOut / FanIn + FanOut

    ​​​​# I 介於 0 ~ 1: 0 最穩定, 1 最不穩定
    ​​​​# FanIn 輸入依賴度: 外部有多少類別會依賴本身元件中的類別
    ​​​​# FanOut 輸出依賴度: 本身元件中有多少類別會依賴外部的類別
    
  • SAP 穩定抽象原則(stable abstracions principle)

    • 「抽象」: 則代表的是 只表達「概念」但並不「實作」
    • 重要的元件, 應該越只表達純粹的「標的(一種概念可已是 需求、目標、行為、分類/歸類)」
    • 核心原則即「隱藏細節」與「抽出標的(可已是 需求、目標、行為)。舉個例子:
      • 設計排程任務,每個排程任務的流程與細節都不同。如果針對「流程」與「細節」去抽象化,那這個抽象只能局限於某個排程使用。
      • 進一步去思考會想到「彈性」、「擴充」、「可讀性」
      • 那對於排程任務這個情境,可以抽出行為的特徵比如像是「初始設定」、「執行任務」 這類標的。
      • 抽出上述標的後可讓抽象變得較為彈性,以達到彈性與多型的需求。
    • 抽象化沒有絕對的對與錯,只有較佳或較適的可行方案。
    • 抽象是設計核心元件的重要指標
    • 抽象是「標的」, 它沒有一個特定的表徵. 舉個例子 =>
    ​​​​ EX => 餐廳與廚師
    ​​​​ # 由廚師本身會煮什麼菜, 來決定餐廳會有什麼樣的菜單. 但對於一定規模的餐聽, 可能不是一個好的情況            
    ​​​​ # 餐廳改成用 菜單 的概念來決定廚師要做哪些事情
    ​​​​ # 就是將表達「概念」的「菜單」, 當成是最穩定的核心元件
    
  • 一般程式架構以常見的依賴關係由核心往外層可分為:infrastructure => domain layer (商業邏輯) => Application layer => User Interface

    • domain layer
      • 通常就是系統的核心, 所以 Domain 的 Service 通常會宣告成 Interface 的介面
      • 創建新的類別實作(implements) 該 Service 的介面
      • 不應直接做資料存取, 比如調用 DAO(指 repository) 來完成資料保存的任務 <= 新觀念
      • 借鑒了「SAP 穩定抽象原則」, 越穩定的元件應該越抽象
    • Application layer
      • 負責流程作業, 相比於 Domain 變動性是比較大的, 雖然同樣有 Service 的類別, 但不創建 Interface 的介面
      • 應該調用了 Domain layer 後, 再調用 DAO <= 新觀念
      • 借鑒了「SDP 穩定依賴原則」把容易變動的東西, 變得更加容易改動
    • Infrastructure => 通常放共用工具的地方
SDP & SAP 兩個原則總結:
#「穩定」與「不穩定」並不是一個「好」與「壞」的關係
# 最容易變動的「User Interface 使用者介面層」、「Application layer 應用層」, 就是放在上兩層, 向下依賴
# 越核心的通常要越少依賴, 且越抽象. !!主要明確行為與特徵. 在測試上也方便抽換!!

MVc 在各大軟體開發商推出的 frameworek, 會讓新手誤以為就是這樣 (觀念修正與思想衝擊)

文章: MVC是一個巨大誤會 框架不應該有「MODELS」資料夾

整理兩篇文章的要點:

  1. 現行 WEB 主流的 MVC 框架, 其實架構大多為 MODEL2
  2. 雖不是 MVC 但 MODLE2 的學習成本很低, 符合商業模式
  3. 不是小白的軟體工程師, 應該準備開始煩惱軟體架構這件事

反思:

  1. 當用了現行別人設計好的框架時, 不小心會掉入舒適圈. (糖果有時是毒藥)
  2. 想當年紅遍全台的 WEB FORM, 為什麼新專案已不見蹤影. (經歷過的就知道再說什麼)
  3. 多想想與試著了解: 為什麼會誕生、簡單的概念、怎麼達成的、簡單的原理