DesignPattern系列 04黎克特制替換原則

2021-09-25 21:23:23 字數 2251 閱讀 4846

在繼承中,凡是在父類已經實現的方法,其實算是一種契約或者規範,子類不應該在進行更改(重寫);但是,由於這一點不是強制要求,所以當子類進行重寫的時候,就會對繼承體系產生破壞。

同時,繼承帶來便利的時候,也有弊端:給程式帶來了侵入性,增加了物件之間的耦合性,可移植性低。當你修改基類時,子類都需要進行相應的修改。

那麼,如何能夠保持繼承的優點,同時減少缺點對程式的影響呢?也就是我們要討論的主角——「黎克特制替換原則」。

如果對每乙個型別為s的物件o1, 都用型別為t的物件o2, 使得以t定義的所有程式p在所有的物件o1都替換為o2時,程式p的行為沒有發生變化,那麼型別s是型別t的子型別。

所有引用基類的地方都必須能透明地使用其子類進行替換。

第二種型別通俗易懂,就是說,只要父類出現的地方,都應該能用其子類進行替換。 但是反過來卻不一定成立,也就是子類所在的地方替換成父類,是不一定成立的。

根據定義,我們總結出以下幾點:

結合**理解一下:

public abstract class superclass 

//定義乙個加法運算函式

public int add(int i, int j)

}public class subclass extends superclass

//子類特有的方法

public void selfmethod()

//子類重寫了父類的非抽象加法運算方法

@override

public int add(int i, int j)

}public class client

}//執行結果如下:

父類被執行...

子類特有的方法

result = -11

當你繼承乙個基類時,編譯器會要求你來實現基類的抽象方法,否則,會報錯。

但是,對於已經實現的方法,編譯器便不會強制讓你去重寫(也不推薦這樣做):在上面的demo中,子類重寫了父類的add方法,在呼叫時,出現了錯誤(基類定義的加法邏輯,被子類重寫為了乙個減法)。這樣子,在父類出現的地方,不能由子類完全替換,違背了「黎克特制替換原則」。

在上面的demo中,子類定義了特有的方法selfmethod(),可以實現其他的業務邏輯。

//子類特有的方法

public void selfmethod()

下來看一下demo:

public class father 

}public class son extends father

}public class client1

public static void invoke()

//執行結果:父類執行...

在demo中,基類定義了乙個dosomething方法,接受的形參型別為hashmap,子類過載了基類的這個方法,並且將接受的形參型別擴充套件為map。但是,我們發現,在父類出現的地方,替換為子類後,執行的結果不變。也就是說,子類物件在方法執行時被替換為父類物件,過載的方法並未被執行。如果想要執行子類的方法,就必須重寫,這是正確的。

如果反過來呢?下面通過反證來證明第三點:

當子類的方法中的前置條件比父類小的時候,情況會怎麼樣呢?

在父類和子類中重新定義這兩個方法,符合子類的前置條件小於父類這一條件即可。

//修改父類的方法,前置條件擴大為map

public collection dosomething(map map)

//修改子類,前置條件縮小為hashmap

public collection dosomething(hashmap map)

當客戶端的invoke()方法中,通過father型別呼叫dosomething方法時,執行結果如下:

//執行結果: 父類執行****

將物件換成son型別時,執行結果時:

public static void invoke() 

//執行結果: 子類被執行...

我們看到了,子類並沒有重寫父類的方法,但是子類的方法被執行了(這是因為呼叫方法時,優先選擇引數型別一致的方法,也就是過載方法,找不到的話才去找型別為形參的基類的方法),但是,這個現象在邏輯上面是錯誤的。

這一點是重寫的要求之一,在這裡就用**展示了。

在前面的示例中,我們在子類subclass中不小心重寫了基類supclass已經實現的方法add(),導致出現了邏輯錯誤。

DesignPattern系列 09設計模式概述

設計模式是程式設計師在面對同類軟體工程設計問題所總結出來的有用的經驗,模式不是 而是某類問題的通用解決方案,設計模 design pattern 代表了最佳的實踐。這些解決方案是眾多軟體開發人員經過相當長的一段時間的試驗和錯誤總結出來的。設計模式的本質提高 軟體的維護性,通用性和擴充套件性,並降低軟...

Design Pattern 工廠模式

當有一些要例項化的具體類,究竟例項化哪個類,要在執行時由一些條件來決定。當 使用大量具體類時,我們就要考慮使用工廠模式了。定義了乙個建立物件的介面,但由子類決定要例項化的類是哪乙個。工廠方法讓類把例項化推遲到子類。public abstract class pizzastore protected ...

design pattern 外觀模式

針對問題 在軟體開發系統中,客戶程式經常會與複雜系統的內部子系統之間產生耦合,而導致客戶程式隨著子系統的變化而變化。那麼如何簡化客戶程式與子系統之間的互動介面?如何將複雜系統的內部子系統與客戶程式之間的依賴解耦?為子系統中的一組介面提供乙個一致的介面,facade 模式定義了乙個高層介面,這個介面使...