定義:一個類、模塊和函數應該對擴展開放,對修改關閉。java
舉例說明什麼是開閉原則,以書店銷售書籍爲例,其類圖以下:
項目上線,書籍正常銷售,可是咱們常常由於各類緣由,要打折來銷售書籍,這是一個變化,咱們要如何應對這樣一個需求變化呢?
咱們有下面三種方法能夠解決此問題:算法
爲何使用(好處)ide
如何實現函數
定義:全部引用基類(父類)的地方必須能透明地使用其子類的對象。通俗講:子類能夠擴展父類的功能,但不能改變父類原有的功能。spa
爲何使用(好處)設計
缺點code
實現原則對象
舉例逐個講解blog
子類能夠實現父類的抽象方法,可是不能覆蓋父類的非抽象方法。
在咱們作系統設計時,常常會設計接口或抽象類,而後由子類來實現抽象方法,這裏使用的其實就是里氏替換原則。子類能夠實現父類的抽象方法很好理解,事實上,子類也必須徹底實現父類的抽象方法,哪怕寫一個空方法,不然會編譯報錯。里氏替換原則的關鍵點在於不能覆蓋父類的非抽象方法。父類中凡是已經實現好的方法,其實是在設定一系列的規範和契約,雖然它不強制要求全部的子類必須聽從這些規範,可是若是子類對這些非抽象方法任意修改,就會對整個繼承體系形成破壞。如:類C1繼承類C時,能夠添加新方法完成新增功能,儘可能不要重寫父類C的方法。不然可能帶來難以預料的風險:繼承
public class C { public int func(int a, int b){ return a+b; } } public class C1 extends C{ @Override public int func(int a, int b) { return a-b; } } public class Client{ public static void main(String[] args) { C c = new C1(); System.out.println("2+1=" + c.func(2, 1)); } }
運行結果:2+1=1
上面的運行結果明顯是錯誤的。類C1繼承C,後來須要增長新功能,類C1並無新寫一個方法,而是直接重寫了父類C的func方法,違背里氏替換原則,引用父類的地方並不能透明的使用子類的對象,致使運行結果出錯。
子類中能夠增長本身特有的方法
在繼承父類屬性和方法的同時,每一個子類也均可以有本身的個性,在父類的基礎上擴展本身的功能。前面其實已經提到,當功能擴展時,子類儘可能不要重寫父類的方法,而是另寫一個方法,因此對上面的代碼加以更改,使其符合里氏替換原則,代碼以下:
public class C { public int func(int a, int b){ return a+b; } } public class C1 extends C{ public int func2(int a, int b) { return a-b; } } public class Client{ public static void main(String[] args) { C1 c = new C1(); System.out.println("2-1=" + c.func2(2, 1)); } }
運行結果:2-1=1
當子類覆蓋或實現父類的方法時,方法的前置條件(即方法的形參/入參)要比父類方法的輸入參數更寬鬆
代碼示例
import java.util.HashMap; public class Father { public void func(HashMap m){ System.out.println("執行父類..."); } } import java.util.Map; public class Son extends Father{ public void func(Map m){//方法的形參比父類的更寬鬆 System.out.println("執行子類..."); } } import java.util.HashMap; public class Client{ public static void main(String[] args) { Father f = new Son();//引用基類的地方能透明地使用其子類的對象。 HashMap h = new HashMap(); f.func(h); } }
運行結果:執行父類...
注意Son類的func方法前面是不能加@Override註解的,由於不然會編譯提示報錯,由於這並非重寫(Override),而是重載(Overload),由於方法的輸入參數不一樣。
當子類的方法實現父類的抽象方法時,方法的後置條件(即方法的返回值)要比父類更嚴格。
代碼示例:
import java.util.Map; public abstract class Father { public abstract Map func(); } import java.util.HashMap; public class Son extends Father{ @Override public HashMap func(){//方法的返回值比父類的更嚴格 HashMap h = new HashMap(); h.put("h", "執行子類..."); return h; } } public class Client{ public static void main(String[] args) { Father f = new Son();//引用基類的地方能透明地使用其子類的對象。 System.out.println(f.func()); } }
執行結果:{h=執行子類...}
持續更新中。。。