什么是里氏替换原则?
里氏替换原则(Liskov Substitution Principle LSP)由麻省理工学院计算机科学实验室的Liskov女士在1987 年的“面向对象技术的高峰会议”(OOPSLA)上发表的一篇文章《数据抽象和层次》(Data Abstraction and Hierarchy)里提出来的,她提出:继承必须确保超类所拥有的性质在子类中仍然成立。
Liskov女士是美国计算机科学家,是08年图灵奖获得者 & 04年冯诺依曼奖得主,是美国工程院院士 & 美国艺术与科学院院士 & 美国计算机协会会士,也是美国第一位计算机女博士。
里氏替换原则是面向对象设计的基本原则,是继承复用的基石。
通俗一点讲就是,LSP要求在软件代码中,父类对象出现的地方被替换成子类可以无差错的运行。换言之,引用基类的地方必须能够透明的使用子类对象,行为不会改变。
里氏替换原则的约束
要实现上述目标,意味着符合里氏替换原则的设计需要满足如下约束:
确保继承体系模塑的是IS-A关系,子类对象可以完全替代父类对象。
应把基类设计成抽象类,而非具象类;应从抽象类派生子类,而不应从具象类继承。
子类应该实现父类的抽象方法,而不应该重写父类的已实现方法。
子类可以扩充新的功能,而不应该改变父类已有的功能。
子类不能增添任何父类没有的附加约束。
里氏替换原则能带来哪些好处?
里氏替换原则符合开闭原则(对扩展开放对修改封闭)的设计要求,子类可以扩充父类功能,而不会改变父类的功能。
它克服了继承中重写父类造成的可复用性变差的缺点。
它为系统正确性提供保障,即类的扩展不会给已有的系统引入新的错误,降低了代码出错的可能性。
实施要点
行为集中的方向向上(向抽象基类的方向),数据集中的方向向下(向具象子类的方向)
违背LSP的最常见情况就是父子类都是可实例化的可具象类,不应该从可具象的类派生,而应该从抽象类或者接口派生。
基于契约的设计(DBC:Design By Contract),契约是通过为每个函数声明的前置条件和后置条件来指定的,要是一个方法得以正确执行,调用者需要确保满足前置条件,实现者需要确保符合后置条件。
经典示例
正方形不是长方形
鸵鸟不是鸟