介面定義類別必須實現的契約或一組方法和屬性。介面用於確保類別遵循某種格式,但它們不提供方法的實現,僅提供方法的簽名。
每當一個類別實作一個介面時,它就會簽署該介面的所有契約(方法和屬性)。每個屬性和方法都是強制實現的。
SOLID 是一個縮寫詞,代表物件導向程式設計的五個基本原則,由 Robert C. Martin(鮑伯大叔)提出。在這裡您可以閱讀有關他的文章的更多資訊。
這些原則旨在改進程式碼的結構和維護,使其更加靈活、可擴展且更易於理解。這些原則可以幫助程式設計師創建更有組織的程式碼、劃分職責、減少依賴、簡化重構過程並促進程式碼重複使用。
縮寫中的「L」代表「里氏替換原理」。 Bob叔叔用來定義這個原則的一句話是:
「衍生類別必須能夠完全替換基底類別」
因此建議衍生類別應該盡可能接近基底類別,這樣派生類別就可以在程式碼不做任何修改的情況下替換其基底類別。
此原則由 Barbara Liskov 於 1988 年基於資料抽象化和類型理論提出。源自契約式設計 (DBC) 的概念,由 Bertrand Meyer 於 1986 年推廣。
這項原則的另一個具體說明是:
子類型應該用作您的基本類型,沒有任何意外。
在程式設計中,變化和意外可能會導致問題。如果需要更換某項系統功能,新功能必須提供相同類型的信息,否則系統可能會發生故障。為了確保類別 S 具有與基底類別 T 相同的行為,必須使用定義實作新功能的強制方法的契約(介面或抽象類別),以確保類別 S 之間相似性的完整性和 T 類別。
考慮一個帶有 Fly() 方法的 Bird 基類,該方法將在兩個子類中使用:Sparrow 和 Ostrich。
檔:bird.java
class Bird { void fly() { System.out.println("I can fly!"); } } class Sparrow extends Bird { // Herda o comportamento de 'fly' da classe 'Bird' } class Ostrich extends Bird { @Override void fly() { throw new UnsupportedOperationException("I cannot fly"); } }
文件:bird.ts
class Bird { fly() { console.log("I can fly!"); } } class Sparrow extends Bird {} class Ostrich extends Bird { fly() { throw new Error("I cannot fly"); } }
在這裡,Sparrow 類遵循 LSP,因為麻雀確實可以飛。然而,Ostrich 類別違反了 LSP,因為它重寫了 voo() 方法,從根本上改變了其行為,打破了 Ave 類別設定的期望。
我們需要透過將Sparrow 和Ostrich 類別的每個特殊性劃分為合約(介面或抽象類,這裡我將使用介面)來應用LSP,它們必須簽署這些合約來調整每個類別的行為:
檔:bird.java
interface Bird { String getName(); void makeSound(); } interface FlyingBird extends Bird { void fly(); } class Sparrow implements FlyingBird { private String name; public Sparrow(String name) { this.name = name; } @Override public String getName() { return this.name; } @Override public void makeSound() { System.out.println("Chirp chirp!"); } @Override public void fly() { System.out.println(this.name + " is flying!"); } } class Ostrich implements Bird { private String name; public Ostrich(String name) { this.name = name; } @Override public String getName() { return this.name; } @Override public void makeSound() { System.out.println("Boom boom!"); } } public class Main { public static void main(String[] args) { Sparrow sparrow = new Sparrow("Little Sparrow"); sparrow.makeSound(); // Chirp chirp! sparrow.fly(); // Little Sparrow is flying! Ostrich ostrich = new Ostrich("Ostrich"); ostrich.makeSound(); // Boom boom! ostrich.fly(); // Error: Method 'fly' does not exist on 'Ostrich' } }
文件:bird.ts
interface Bird { name: string; makeSound(): void; } interface FlyingBird extends Bird { fly(): void; } class Sparrow implements FlyingBird { name: string; constructor(name: string) { this.name = name; } makeSound() { console.log("Chirp chirp!"); } fly() { console.log(`${this.name} is flying!`); } } class Ostrich implements Bird { name: string; constructor(name: string) { this.name = name; } makeSound() { console.log("Boom boom!"); } } const sparrow = new Sparrow("Little Sparrow"); sparrow.makeSound(); // Chirp chirp! sparrow.fly(); // Little Sparrow is flying! const ostrich = new Ostrich("Ostrich"); ostrich.makeSound(); // Boom boom! ostrich.fly(); // Error: Method 'fly' does not exist on 'Ostrich'
更正說明
Bird Interface:定義所有鳥類共有的行為,例如makeSound()。所有鳥類都必須實作此介面。
FlyingBird 介面:繼承自 Ave 並添加 Fly() 行為,該行為特定於會飛的鳥類。
Sparrow 類別:實作 FlyingBird 接口,因為麻雀可以飛。此類定義了發出聲音和飛行的行為。
鴕鳥類:僅實現 Bird 接口,因為鴕鳥不會飛。類別沒有 Fly() 方法,因此不違反 LSP。
LSP 對於確保程式碼模組化、可重複使用且易於維護至關重要。違反 LSP 可能會導致脆弱的程式碼在引入新子類別或修改現有子類別時中斷,因為這可能會導致依賴超類別的部分程式碼出現意外行為。
子類型替換允許模組無需修改即可擴展,這對於開閉原則 (OCP) 提供的靈活性至關重要,而里氏替換原則使之成為可能。契約(透過介面或抽象類別實現)對於安全設計至關重要,但程式設計師必須充分理解它們,有助於避免遺留軟體中的常見錯誤。他們還提供了有關如何實施和使用程式碼的寶貴指導,只需遵守相關合約即可。
理解並應用里氏替換原則可以幫助開發人員創建更可預測和穩定的物件導向系統。
以上是在 Typescript 和 Java 中應用'里氏替換原則”的詳細內容。更多資訊請關注PHP中文網其他相關文章!