「這是我參與8月更文挑戰的第4天,活動詳情查看:8月更文挑戰」前端
在面試高級前端時,每每會遇到一些關於設計模式的問題,每次都回答不太理想。恰逢8月更文挑戰的活動,準備用一個月時間好好理一下關於設計模式方面的知識點,給本身增長點面試的底氣。web
在學習設計模式以前,首先要認識到設計模式是個編程思想,對任何編程語言都適用。其次要從設計模式的原則開始學習,故本文將詳細介紹設計模式的原則之一里氏代換原則。面試
若是對每個類型爲T1的對象o1,都有類型爲T2的對象o2,使得以T1定義的全部程序P在全部的對象o1都換成o2時,程序P的行爲沒有變化,那麼類型T2是類型T1的子類型。編程
官方的定義讓人摸不着頭腦,用白話文描述:在程序中,把父類都替換成它的子類,程序仍是能正常運行。設計模式
里氏代換原則是開放-封閉原則的前提,爲何這麼說呢?在開放-封閉原則中,父類保持封閉,用子類繼續父類的方式,對父類進行擴展,實現開放。父類保持封閉,此時父類是能夠被複用的。然而在實際開發過程當中,在繼承父類建立一個子類過程,常常會犯一毛病,在子類中去修改父類的方法和屬性,這就致使父類不在封閉,若是父類被複用了,頗有可能出現意想不到的BUG。api
舉個例子來講明:瀏覽器
class A {
constructor() {
}
storageData() {
api.getTaskList1()
.then(res =>{
localStorage.setItem(taskData", JSON.stringify(res.data) );
})
}
}
class B extends A {
constructor() {
super();
}
storageData() {
api.getTaskList2()
.then(res =>{
localStorage.setItem("taskData", JSON.stringify(res.data));
})
}
}
複製代碼
上述代碼中,子類B繼承父類A,假設在程序中執行const a = new A();a.storageData();
請求getTaskList1接口將其獲取的數據緩存到瀏覽器的Local Storage的taskData中。緩存
然而在某個地方,不經意執行了const a = new B();a.storageData();
,此時變成請求getTaskList1接口將其獲取的數據緩存到瀏覽器的Local Storage的taskData中,把瀏覽器的Local Storage中taskData的值給替換了,致使在程序中使用瀏覽器的Local Storage中的taskData數據的地方出錯了。markdown
若是在開發過程當中,遵循里氏代換原則,這種狀況根本不會發生。按照里氏代換原則,把const a = new A();
替換成const a = new B();
後程序是能夠正常運行的。上面子類B繼承父類A時,在子類B把父類A中的storageData
方法給修改了,致使程序沒法正常運行。編程語言
因此,里氏代換原則有一個更通俗的定義:子類能夠擴展父類的功能,但不能改變父類原有的功能。