里氏替换原则(Liskov Substitution Principle)
LSP的基本概念
- 定义:
- 所有引用基类的地方必须能透明地使用其子类的对象
- 只要父类能出现的地方子类就可出现,而且替换为子类也不会产生任何错误或异常,使用者可能根本就不需要知道是父类还是子类(封装造成的多态性)
- 规范
- 子类必须完全实现父类的方法
在类中调用其他类时必然要使用父类或者接口,如果子类中不支持父类中的方法,自然就违背了LSP
- 子类要有自己的特性
- 子类是在父类的基础上实现的,有自己的特性
- 这也就导致了LSP的单向性,在子类能出现的地方,父类未必能够胜任。
- 比如实际开发中向下转型是不正确的,会抛出ClassCastException异常。
- 覆写或实现父类的方法时参数可以被放大
- 子类中方法的参数的前置条件必须与超类中被覆写的方法的前置条件相同或者更宽松
- 因为参数类型不同会导致参数列表不同,那么实际上我们在参数类型不同时实现的是重载而非覆写
- 所以在子类中方法条件更宽松的情况下,因为重载的调用规则,更加匹配严谨的重载会优先调用,也就意味着我们这个重载不会意外地覆盖父类中的方法(比如HashMap比Map类型会优先被匹配,可能会导致重载达到也向覆写一样覆盖了父类的函数,但是显然这是不符合逻辑的),保证了LSP的正确性。
- 覆写或实现父类的方法时的输出结果可以被缩小
- 这个缩小的具体含义如下:设父类中方法的返回值是T,子类中覆写的方法的返回值是S,那么S要么和T是同类型,要么S是T的子类
- 因为在LSP下,满足缩小条件条件才能保证返回对象在使用时是安全且完整实现的。
- 子类必须完全实现父类的方法
- 优点:采用LSP能够增强程序的健壮性,版本升级使能够巴证非常好的兼容性,即使增加子类,原有的子类还可以继续运行。
因为对于Java语言,LSP已经实现编译期和语言层级的保证,也就是当违反的时候会抛出异常,我们只需要在覆写和重载时遵循LSP即能保证这一原则的保障。
时间: 2024-10-15 14:59:36