里氏替换原则简称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