里氏替換原則簡稱LSP。定義:所有引用基類的地方必須能夠透明地使用其子類的對象。
所謂對象是一組狀態和一系列行爲的組合。狀態是對象的內在特性,行爲是對象的外在特性。LSP所表述的就是在同一個繼承體系中的對象應該有共同的行爲特徵。我們在設計對象時是按照行爲進行分類的,只有行爲一致的對象才能抽象出一個類來。因此,如果說鴕鳥和企鵝屬於鳥類的話,就違背了里氏替換原則。
如何規範地遵從里氏替換原則:
1 子類必須完全實現父類的抽象方法,但不能覆蓋父類的非抽象方法
2 子類可以實現自己特有的方法
3 當子類覆蓋或實現父類的方法時,方法的前置條件(即方法的形參)要比父類方法的輸入參數更寬鬆。
4 當子類的方法實現父類的抽象方法時,方法的後置條件(即方法的返回值)要比父類更嚴格。
5 子類的實例可以替代任何父類的實例,但反之不成立
舉例如下
import abc
class Abstract_bird(object):
__metaclass__ = abc.ABCMeta
@abc.abstractmethod
def fly(self):
pass
@abc.abstractmethod
def tweet(self):
pass
def eat(self):
print('bird is eating')
class Eagle(Abstract_bird):
def fly(self):
print('eagle is flying')
def tweet(self):
print('eagle is tweeting')
def drink(self):
print('eagle is drinking')
if __name__ == '__main__':
bird = Abstract_bird()
bird.fly()
bird.tweet()
bird.eat()
print('把所有父類Abstract_bird替換爲子類Eagle如下')
eagle = Eagle()
eagle.fly()
eagle.tweet()
eagle.eat()
結果如下
bird is eating
把所有父類Abstract_bird替換爲子類Eagle如下
eagle is flying
eagle is tweeting
bird is eating
以上代碼中,實現了父類Abstract_bird和子類Eagle,Abstract_bird類實現了三個方法,方法fly和tweet是抽象方法,方法eat是一般方法。子類Eagle中實現了自己特有的方法drink。以上代碼遵從了里氏替換原則:1 子類必須完全實現父類的抽象方法,但不能覆蓋父類的非抽象方法。2 子類可以實現自己特有的方法。因此,結果也符合預期。但如果讓父類的實例去替換子類的實例的話一定會出錯的,因爲父類中沒有子類特有的方法drink