本次是繼續上回的Clean Code筆記,廢話不多說,Let’s us begin.
TDD Principle
撰寫一個單元測試前不應該撰寫產品程式碼
只撰寫剛好能通過的產品程式碼
只撰寫剛好能通過當前測試失敗的產品程式碼
注意要點
撰寫測試的好處可以讓你更動程式碼時不那麼恐懼, 需要注意的是,測試程式碼同樣需要與時俱進,若沒有跟著調整容易造成程式碼的腐敗,最終測試程式碼的品質同樣影響產品程式碼。
測試程式碼要求的是可讀性 闡明性(Clarity),而不是效能。
盡量維持一個測試一個斷言(Assert),讓一個測試只會顯示一個結果,方便開發者評估功能。(一個測試只測試一個概念)
TDD FIRST原則
Fast 測試應該要夠快
Independent 測試應該要能夠獨立運行,不依賴其他測試程式
Repeatable 測試應該要能夠重複使用
Self-Validating 測試應該要能夠自我驗證,顯示要測試的概念是否成功運作
Timely 要在產品程式之前被撰寫,若是之後才撰寫,經常會發現撰寫出來的產品程式碼並不好被測試
Class-Level 單一職責原則(Single Responsibility Principle, SRP) 單一職責原則主張,一個類別或一個模組應該只能有一個,而且只能有一個被修改的理由。 個人對這段的理解是,一個類別的職責應該是很明確的,他只該負責一件事,而需要修改類別的原因, 必須得是當初認為要做的那件事。 比方說有一個專門處理報表Excel輸出的類別ExcelObject,若今天需要做輸出Excel之外的事 ,比方說:判斷格式、字串拼接、欄位驗證、給定預設值,若因為這些理由而修改了ExcelObject,就是違反了SRP。
凝聚力 類別中的方法,盡量讓每個變數都被使用在每一個方法中。 當類別失去凝聚力時,就應該將它拆開
開放閉合原則(Open-Closed Principle) 類別應該要對擴充具備開放性,但對修改具有閉合性。
隔離修改 類別之間不應該實體依賴,而是依賴抽象,透過一層抽象隔離變化,責任分明且易於測試。
System 依賴注入(Dependency Injection, DI) 將物件的建立過程從使用中分離出來,這是控制反轉(Inversion of Control, IOC)在相依性管理裡的一種應用手段。控制反轉是將某個物件的第二個職責,移至其他專注於該職責的物件裡,也因此支援了SRP原則。 在相依性管理的範疇中,一個物件不應該負責實體化對本身的相依。而是將責任交給外部。建議可以透過抽象工廠進行。
抽象工廠(Abstract Factory) Example 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 interface Button { void render () ; }interface TextBox { void render () ; }class WindowsButton implements Button { @Override public void render () { System.out.println("Rendering a Windows-style Button" ); } }class WindowsTextBox implements TextBox { @Override public void render () { System.out.println("Rendering a Windows-style TextBox" ); } }class MacOSButton implements Button { @Override public void render () { System.out.println("Rendering a MacOS-style Button" ); } }class MacOSTextBox implements TextBox { @Override public void render () { System.out.println("Rendering a MacOS-style TextBox" ); } }interface UIFactory { Button createButton () ; TextBox createTextBox () ; }class WindowsFactory implements UIFactory { @Override public Button createButton () { return new WindowsButton (); } @Override public TextBox createTextBox () { return new WindowsTextBox (); } }class MacOSFactory implements UIFactory { @Override public Button createButton () { return new MacOSButton (); } @Override public TextBox createTextBox () { return new MacOSTextBox (); } }public class AbstractFactoryExample { public static void main (String[] args) { UIFactory factory = getFactory("Windows" ); Button button = factory.createButton(); TextBox textBox = factory.createTextBox(); button.render(); textBox.render(); } private static UIFactory getFactory (String osType) { return switch (osType) { case "Windows" -> new WindowsFactory (); case "MacOS" -> new MacOSFactory (); default -> throw new IllegalArgumentException ("Unknown OS type" ); }; } }
▲ 這樣的設計可以靈活切換不同風格的 UI,且對於新的 UI 主題(如 Linux),只需添加新的工廠和產品類即可,無需修改現有代碼。
橫切關注點 假設我們有一個交易系統,流程如下:
登入-> 身分驗證 -> 付款
登入-> 身分驗證 -> 退款
嘗試以這樣的角度去理解系統的流程,你會發現「登入」與「身分驗證」並不是真正核心的功能,且兩者重複存在。為了使我們可以更專注在真正重要的商業流程上,我們可以將那些次要的細節作為一個個切片(Aspects)從主流程切割出來,這一個步驟我們稱之為關注點分離。 而實現這樣的構想的技術就是Java Proxy機制,或是AOP(又名切面導向編程)。 關於AOP,可以參考我的另一篇文章:Spring AOP
大約整理到這邊,後面Clean Code的相關討論幾乎都是案例題目了,這邊就不拿出來討論了。