黎克特制替換原則(liskov substitution principle,lsp)是指如果對每乙個型別為t的物件o,都有型別為t1的物件o1,使得以t定義的所有程式p在所有的物件o替換為o1是,程式p的行為沒有發生變化,那麼型別t1是型別t的子類。通俗理解是**中任何父類物件可以出現的地方,子類都可以出現,用子類替換父類,不會導致原有的**發生異常。黎克特制替換原則是對開閉原則的補充。
從定義可以看出來,黎克特制替換原則是對實現抽象化的具體步驟的規範,即對有繼承關係的父子類的相互約束。當要設計乙個子類去擴充套件乙個符合規範的父類時,黎克特制替換原則要求約束子類的行為,避免繼承氾濫,比如子類可以新增新的特性,但不應改變父類的行為,這些行為包括覆蓋父類的非抽象方法、降低父類方法的訪問許可權等;或重構**時,重構後的父類和子類,黎克特制替換原則要求父類物件出現的地方,子類物件都可以出現,如果不符合,必然還需要優化或繼續重構**。反之,子類出現的地方,父類不一定可以替換。這裡說的子類不要覆蓋父類非抽象方法,在實際開發中,有一些情況下父類的非抽象方法是可以覆蓋的,即這些父類非抽象方法原本就是設計給子類覆蓋用的,這在一些基於事件處理的框架中很常見,這些父類的非抽象方法為使用框架的使用者提供了處理事件的入口,比如netty框架中提供使用者對通道事件的處理便是如此。
比如乙個教學平台原來設計只有教師使用者teacher登入用來備課。現在增加了教學功能,且新增了學生使用者student可以登入平台學習。下面通過**示例,說明遵循黎克特制替換原則的重要性和必要性。
// 1.原來的教師使用者類
public class teacher
public string getpwd()
public string getteachername()
}// 2.原來的的登入服務介面
public inte***ce loginservice
// 3.原來的使用者登入服務
public class loginserviceimpl implements loginservice
}// 4.原來的教師服務介面
public inte***ce teacherservice
// 5.原來的教師服務
public class teacherserviceimpl implements teacherservice
}
因為新增了學生使用者student,所有抽象乙個使用者user類作為學生和教師的父類,然後再重構使用者登入服務,下面是新增的使用者user類和學生使用者student類
// 6.user類,抽取公共部分
public abstract class user
public string getpwd()
// 使用者角色,有具體子類實現
abstract protected string role();
}// 7.學生使用者
public class student extends user
}// 8.學生服務
public inte***ce studentservice
// 學生服務
public class studentserviceimpl implements studentservice
}
// 1.原來的教師使用者類
// 繼承user類,刪除了父類中有的公共內容
// 只保留教師特有的特性即可
public class teacher extends user
@override
protected string role()
}// 2.原來的的登入服務介面
// 引數使用父類user,讓新增加的student子類可以使用
public inte***ce loginservice
// 3.原來的使用者登入服務
// 重構後,所有user的子類均可以登入,
// user引數替換為teacher或student,預期都一致,
// 遵循黎克特制替換原則
public class loginserviceimpl implements loginservice
}// 4.原來的教師服務介面
// 增加了教學方法
public inte***ce teacherservice
// 5.原來的教師服務
// 增加了教學方法。思考:此處可以使用user替換teacher嗎?
public class teacherserviceimpl implements teacherservice
@override
public void teaching(string course)
}
重構完成後,登入服務中,user可以被替換為student或teacher,滿足學生和教師都可以登入的需求,但教師服務中課程錄製record方法中的teacher則不能替換為user,因為這是教師的特性。重構之後,如果增加後續新的使用者角色,比如家長、輔導員,則不再需要修改原有的**即可實現擴充套件新的使用者角色,這樣提公升了**的可復用和可擴充套件性、以及可維護性。
上面的例子看完可能還有些模糊,但只要記住黎克特制替換原則,一是告訴開發人員,在有需要新特性時才去擴充套件父類,不要為了繼承而繼承。另外就是,在重構**時,重構後的**要遵循黎克特制代換原則,這樣可以最大程度確保重構後的**的復用性和可維護性以及可擴充套件性,讓重構真正有意義或滿足業務需求。
物件導向設計原則 黎克特制替換原則
黎克特制替換原則lsp liskov substitution principle 主要闡述了有關繼承的一些原則。子類可以擴充套件父類的功能,但不能改變父類原有的功能,如果重寫了父類的方法,就會降低整個繼承體系的復用性,如果違背了黎克特制替換原則,就很有可能出現執行錯誤 這裡以乙個鳥的例子來闡述 首...
物件導向設計原則 黎克特制替換原則
黎克特制替換原則是任何基類出現的地方,子類一定可以替換它 是建立在基於抽象 多型 繼承的基礎復用的基石,該原則能夠保證系統具有良好的拓展性,同時實現基於多型的抽象機制,能夠減少 冗餘。黎克特制替換原則要求我們在編碼時使用基類或介面去定義物件變數,使用時可以由具體實現物件進行賦值,實現變化的多樣性,完...
物件導向設計原則 黎克特制替換原則 LSP
要 求 子類可以替換父類並且出現在父類能夠出現的任何地方 這個原則也是在貫徹gof倡導的面向介面程式設計!在這個原則中父類應盡可能使用介面或者抽象類來實現!子類通過實現了父類介面,能夠替父類的使用地方!通過這個原則,我們客戶端在使用父類介面的時候,通過子類實現!意思就是說我們依賴父類介面,在客戶端宣...