SOLID 是一組基本原則,旨在增強物件導向程式設計 (OOP) 中程式碼的可管理性和可擴展性。它由五個關鍵原則組成:
這些原則是由 Robert C. Martin(也稱為 Uncle Bob)在 2000 年代初期提出的,此後已在軟體開發社群中廣泛採用。透過遵循 SOLID 原則,開發人員可以創建更易於理解、修改和擴展的程式碼,從而形成更強壯和可維護的軟體系統。
單一職責原則是 OOP 和 SOLID 中第一個也是最基本的原則。顧名思義,這原則的意思是「一個類別應該只負責一個特定的責任」。
假設我們有一個名為 Invoice 的類,其中包含 2 個方法generateInvoice() 和 saveToFiles() 。
public class Invoice { private Long InvoiceNo; public void generateInvoice() { // code to generate Invoice. } public void saveToFiles() { // code to save invoice as a file. } }
這不是一個好的做法,因為 Invoice 類別有兩個職責。更好的方法是將這些功能分成專用的類別。
public class Invoice { private Long InvoiceNo; public void generateInvoice() { // code to generate Invoice. } } public class FileManager { public void saveToFiles(Invoice invoice) { // code to save invoice as a file. } }
在這裡,我們可以看到我們有 2 個用於用例的類別:
開閉原則是SOLID的另一個核心原則。此原則由 Bertrand Meyer 於 1997 年提出。這個原則背後的想法是「軟體工件(類別、模組和函數)應該對擴展開放,但對修改關閉。」
例如;
比方說,我們有一個名為 Shape 的類,我們可以用這個類來計算形狀的面積。
public class Invoice { private Long InvoiceNo; public void generateInvoice() { // code to generate Invoice. } public void saveToFiles() { // code to save invoice as a file. } }
在上面的程式碼中,新增形狀需要修改現有的 Shape 類,這不是一個好的做法。
以下是一個程式碼範例,示範如何將開閉原則應用於此場景。
public class Invoice { private Long InvoiceNo; public void generateInvoice() { // code to generate Invoice. } } public class FileManager { public void saveToFiles(Invoice invoice) { // code to save invoice as a file. } }
透過OCP的應用,我們可以在不修改目前實現的情況下添加許多我們想要的形狀。
注意:使用介面並不是實現 OCP 的唯一方法。
里氏替換原則是 OOP 中的另一個重要原則。它是由 Barbara Liskov 於 1987 年在一次關於資料抽象的會議演講中引入的。
該原則指出,「超類別的物件應該可以用其子類別的物件替換,而不改變程式的正確性」。
例如,如果 Circle 和 Rectangle 是 Shape 的子類型,那麼我們應該能夠用 Circle 或 Rectangle 物件取代 Shape 對象,不會有任何問題。
public class Shape { private String shapeType; private double radius; private double length; private double width; public Shape(String shapeType, double radius, double length, double width) { this.shapeType = shapeType; this.radius = radius; this.length = length; this.width = width; } public double area() { if (shapeType.equals("circle")) { return Math.PI * (radius * radius); } else if (shapeType.equals("rectangle")) { return length * width; } else { throw new IllegalArgumentException("Unknown shape type"); } } } // Usage public class Main { public static void main(String[] args) { Shape circle = new Shape("circle", 5, 0, 0); Shape rectangle = new Shape("rectangle", 0, 4, 6); System.out.println(circle.area()); System.out.println(rectangle.area()); } }
如本例所示,遵循里氏替換原則意味著我們應該能夠無縫地用子類別實例取代超類別實例。
介面隔離原則是 Robert C. Martin 提出的五個 SOLID 原則之一。它指出:「不應強迫客戶端依賴他們不使用的介面」。
換句話說,使用多個特定於任務的介面比使用一個通用介面更好。
下面的範例展示了通用介面的用法。
public class Invoice { private Long InvoiceNo; public void generateInvoice() { // code to generate Invoice. } public void saveToFiles() { // code to save invoice as a file. } }
使用像 MultifunctionPrinter 這樣的通用介面迫使我們實作不必要的方法,這被認為是不好的做法。讓我們探討一下如何將介面隔離原則套用到此場景。
public class Invoice { private Long InvoiceNo; public void generateInvoice() { // code to generate Invoice. } } public class FileManager { public void saveToFiles(Invoice invoice) { // code to save invoice as a file. } }
public class Shape { private String shapeType; private double radius; private double length; private double width; public Shape(String shapeType, double radius, double length, double width) { this.shapeType = shapeType; this.radius = radius; this.length = length; this.width = width; } public double area() { if (shapeType.equals("circle")) { return Math.PI * (radius * radius); } else if (shapeType.equals("rectangle")) { return length * width; } else { throw new IllegalArgumentException("Unknown shape type"); } } } // Usage public class Main { public static void main(String[] args) { Shape circle = new Shape("circle", 5, 0, 0); Shape rectangle = new Shape("rectangle", 0, 4, 6); System.out.println(circle.area()); System.out.println(rectangle.area()); } }
透過應用ISP,我們將其分成更小的、特定於角色的介面 ——例如印表機、掃描器和傳真。這允許每個類別(例如 BasicPrinter、AdvancedPrinter 或 FaxMachine)僅實現相關功能,從而促進模組化並減少不必要的依賴關係。
依賴倒置原則是SOLID的最終原則。這也是由 Robert C. Martin 介紹的。這促進了鬆散耦合的程式碼。
DIP說明了幾點:
簡單來說,一個類別不應該直接依賴其他特定類別(具體實作),而應該依賴介面或抽象類別。這使得程式碼更加靈活且更易於維護,因為您可以在不更改依賴類別的情況下更換實作。
public class Invoice { private Long InvoiceNo; public void generateInvoice() { // code to generate Invoice. } public void saveToFiles() { // code to save invoice as a file. } }
如上例所示,Computer 類別直接依賴 Keyboard 類別。
public class Invoice { private Long InvoiceNo; public void generateInvoice() { // code to generate Invoice. } } public class FileManager { public void saveToFiles(Invoice invoice) { // code to save invoice as a file. } }
現在,Computer 依賴 InputDevice 接口,而不是特定的 Keyboard。這樣可以輕鬆切換到另一個輸入設備,例如 WirelessKeyboard,而無需修改 Computer 類別。
總而言之,SOLID 原則:單一職責、開閉、里氏替換、介面隔離和依賴倒置為在物件導向程式設計中編寫乾淨、可維護和可擴展的程式碼提供了基本準則。
透過遵守這些原則,開發人員可以創建更易於理解、修改和擴展的系統,最終帶來更高品質的軟體和更有效率的開發流程。
感謝您閱讀這篇文章!我希望您現在對 SOLID 原則以及如何應用它們來增強您的專案有了深入的了解。
追蹤我:
—薩迪莎·尼薩拉
以上是堅實的原則的詳細內容。更多資訊請關注PHP中文網其他相關文章!