里氏替換原則
- java OO 中繼承性的思考和說(shuō)明:
- 繼承包含這樣一層含義:父類中凡是已經(jīng)實(shí)現(xiàn)好的方法务热,實(shí)際上就是在設(shè)定規(guī)范和契約鞠鲜,雖然它不強(qiáng)制要求所有的子類必須遵循這些契約冲粤,但是如果子類對(duì)這些已經(jīng)實(shí)現(xiàn)的方法任意修改祝闻,就會(huì)對(duì)這個(gè)繼承體系造成破壞。
- 繼承在給程序設(shè)計(jì)帶來(lái)便利的同時(shí)是牢,也帶來(lái)了弊端碉克。比如使用繼承會(huì)給程序帶來(lái) 傾入性凌唬,程序的可移植性就會(huì)降低,會(huì)增加對(duì)象間的耦合性漏麦,如果一個(gè)類被其他的類所繼承,則當(dāng)這個(gè)類需要修改的時(shí)候况褪,即 當(dāng)父類需要修改的時(shí)候撕贞,必須要考慮到子類,因?yàn)榭赡芨割愋薷暮蟛舛猓欣^承的子類的功能方法都有可能產(chǎn)生問(wèn)題故障
- 在實(shí)際編程中捏膨,如何正常的使用繼承----- 里氏替換原則
- 里氏替換原則介紹:
- 如果對(duì)每個(gè)類型為 T1 的對(duì)象 O1,都有類型為 T2 的對(duì)象 O2,使得以 T1 定義的所有程序 P 在所有的對(duì)象 O1 都待換成 O2 時(shí)号涯,程序 P 的行為沒(méi)有發(fā)送變化目胡,那么類型 T2 是類型 T1 的子類型。換句話說(shuō)链快,所有引用基類的地方必須能透明的使用其子類的對(duì)象誉己。
- 在使用繼承的時(shí)候,遵循里氏替換原則域蜗,在 子類中盡量不要重寫(xiě)父類的方法
- 里氏替換原則告訴我們巨双,繼承實(shí)際上讓兩個(gè)類 耦合性 增強(qiáng)了 (通俗的說(shuō),子類繼承了父類霉祸,父類一旦變化了筑累,子類就必須要跟著變了,所以說(shuō)耦合性增強(qiáng)了)丝蹭,在適當(dāng)?shù)那闆r下慢宗,可以通過(guò) 聚合,組合奔穿,依賴 來(lái)解決問(wèn)題镜沽。
案例
- 代碼案例
public class Liskov {
public static void main(String[] args) {
A a = new A();
System.out.println("11-3=" + a.func1(11, 3));
System.out.println("1-8=" + a.func1(1, 8));
System.out.println("-----------------------");
B b = new B();
System.out.println("11-3=" + b.func1(11, 3));//這里本意是求出11-3
System.out.println("1-8=" + b.func1(1, 8));// 1-8
System.out.println("11+3+9=" + b.func2(11, 3));
}
}
// A 類
class A {
// 返回兩個(gè)數(shù)的差
public int func1(int num1, int num2) {
return num1 - num2;
}
}
// B 類繼承了A
// 增加了一個(gè)新功能:完成兩個(gè)數(shù)相加,然后和9 求和
class B extends A {
//這里淘邻,重寫(xiě)了A 類的方法, 可能是無(wú)意識(shí)
public int func1(int a, int b) {
return a + b;
}
public int func2(int a, int b) {
return func1(a, b) + 9;
}
}
- 解決方法
- 我們發(fā)現(xiàn)原來(lái)正常的減法功能發(fā)生了錯(cuò)誤宾舅。原因就是類 B 無(wú)意中重寫(xiě)了父類的方法,造成原有功能出現(xiàn)錯(cuò)誤蔬蕊。在實(shí)際編程中,我們常常會(huì)通過(guò)重寫(xiě)父類的方法完成新的功能猜扮,這樣寫(xiě)起來(lái)雖然簡(jiǎn)單旅赢,但整個(gè)繼承體系的復(fù)用性會(huì)比較差煮盼。特別是運(yùn)行多態(tài)比較繁瑣的時(shí)候
- 通用的方法就是: 原有的父類和子類都繼承一個(gè)更加通俗的 BaseClass 基礎(chǔ)類香到,并且將原本的父類與子類之間的繼承關(guān)系去掉养渴,采用 依賴,聚合藐唠,組合 等關(guān)系替代
-
改進(jìn)方案:
父類與子類繼承更加基礎(chǔ)的Base類
改進(jìn)
- 代碼
public class Liskov {
public static void main(String[] args) {
A a = new A();
System.out.println("11-3=" + a.func1(11, 3));
System.out.println("1-8=" + a.func1(1, 8));
System.out.println("-----------------------");
B b = new B();
//因?yàn)锽 類不再繼承A 類自赔,因此調(diào)用者润脸,不會(huì)再func1 是求減法
//調(diào)用完成的功能就會(huì)很明確
System.out.println("11+3=" + b.func1(11, 3));//這里本意是求出11+3
System.out.println("1+8=" + b.func1(1, 8));// 1+8
System.out.println("11+3+9=" + b.func2(11, 3));
//使用組合仍然可以使用到A 類相關(guān)方法
System.out.println("11-3=" + b.func3(11, 3));// 這里本意是求出11-3
}
}
//創(chuàng)建一個(gè)更加基礎(chǔ)的基類
class Base {
//把更加基礎(chǔ)的方法和成員寫(xiě)到Base 類
}
// A 類繼承 Base 基礎(chǔ)類
class A extends Base {
// 返回兩個(gè)數(shù)的差
public int func1(int num1, int num2) {
return num1 - num2;
}
}
// B 類繼承 Base 基礎(chǔ)類
class B extends Base {
//如果B 需要使用A 類的方法,使用組合關(guān)系
private A a = new A();
//這里灾测,重寫(xiě)了A 類的方法, 可能是無(wú)意識(shí)
public int func1(int a, int b) {
return a + b;
}
public int func2(int a, int b) {
return func1(a, b) + 9;
}
//我們?nèi)匀幌胧褂肁 的方法
public int func3(int a, int b) {
return this.a.func1(a, b);
}
}