裡氏置換原則(Liskov Substitution Principle),簡稱LSP
定義:
Functions that use pointers or references to base classes must be able to use objects of derived classes without knowing it.
所有引用基類的地方必須能夠透明的使用其子類對象。
也就是說,只要父類出現的地方子類就能夠出現,而且替換為子類不會產生任何錯誤或異常。但是反過來,子類出現的地方,替換為父類就可能出現問題了。
這個原則是為良好的繼承定義一個規范,簡單的講,有4層含義:
一、子類必須完全實現父類的方法
定義一個抽象類
public abstract class ViewPoint {
//去麗江旅游
public abstract void where();
}
下面兩個類是實現這個抽象類
public class Lijiang extends ViewPoint {
@Override
public void where() {
System.out.println("歡迎來到麗江...");
}
}
public class Zhangjiajie extends ViewPoint {
@Override
public void where() {
System.out.println("歡迎來到張家界...");
}
}
人物是塗塗,在裡面設置類類型來傳遞參數。此時塗塗要去的旅游景點還是抽象的
public class Tutu {
//定義要旅游的景點
private ViewPoint viewpoint;
//塗塗要去的景點
public void setViewPoint(ViewPoint viewpoint)
{
this.viewpoint = viewpoint;
}
public void travelTo()
{
System.out.println("塗塗要去旅游了");
viewpoint.where();
}
}
場景類。設置具體要去的景點
public class Sence {
public static void main(String args[])
{
Tutu tutu = new Tutu();
//設置要去的旅游景點
tutu.setViewPoint(new Lijiang());
tutu.travelTo();
}
}
運行結果:
塗塗要去旅游了
歡迎來到麗江...
二、子類可以有自己的特性
也就是說在類的子類上,可以定義其他的方法或屬性www.2cto.com
三、覆蓋或者實現父類的方法時輸入參數可以被放大
父類能夠存在的地方,子類就能存在,並且不會對運行結果有變動。反之則不行。
父類,say()裡面的參數是HashMap類型,是Map類型的子類型。(因為子類的范圍應該比父類大)
import java.util.Collection;
import java.util.HashMap;
public class Father {
public Collection say(HashMap map)
{
System.out.println("父類被執行...");
return map.values();
}
}
子類,say()裡面的參數變成了Map類型,Map范圍比HashMap類型大,符合LSP原則。注意這裡的say不是覆寫父類的say,因為參數類型不同。而是重載。
import java.util.Collection;
import java.util.Map;
/*
* 子類繼承了父類的所有屬性
*/
public class Son extends Father {
//方法輸入參數類型
public Collection say(Map map)
{
System.out.println("子類被執行...");
return map.values();
}
}
場景類
import java.util.HashMap;
public class Home {
public static void main(String args[])
{
invoke();
}
public static void invoke()
{
//父類存在的地方,子類就應該能夠存在
//Father f = new Father();
Son s = new Son();
HashMap map = new HashMap();
//f.say(map);
s.say(map);
}
}
無論是用父類還是子類調用say方法,得到的結果都是
父類被執行...
但是,如果將上面Father裡的say參數改為Map,子類Son裡的say參數改為HashMap,得到的結果就變成了
f.say(map)結果:父類被執行...
s.say(map)結果: 子類被執行...
這樣會造成邏輯混亂。所以子類中方法的前置條件必須與父類中被覆寫的前置條件相同或者更寬。
四、覆寫或者實現父類的方法時輸出結果可以被縮小
其實與上面的類似,也就是父類能出現的地方子類就可以出現,而且替換為子類不會產生任何錯誤或者異常,使用者也無需知道是父類還是子類。但是反過來就不行了,有子類出現的地方,父類未必就適應。(畢竟子類的范圍要>=父類的范圍)
作者 婁立軍