ser*_*0ne 1 liskov-substitution-principle solid-principles
里氏替换原则指出:
程序中的对象应该可以用其子类型的实例替换,而不改变该程序的正确性。
假如说:
interface Iterable<T> {
fun getIterator(): Iterator<T>
}
interface Collection<T> : Iterable<T> {
val size: Int
}
interface List<T> : Collection<T> {
fun get(index: Int): T
}
interface MutableList<T> : List<T> {
fun set(index: Int, item: T): Unit
}
Run Code Online (Sandbox Code Playgroud)
当 LSP 应用于输入参数时,应应用最低级别的抽象:
做
fun foo(items: Iterable<Any>) { ... }
Run Code Online (Sandbox Code Playgroud)
不
fun foo(items: List<Any>) { ... }
Run Code Online (Sandbox Code Playgroud)
但是,LSP 是否适用于函数返回类型?如果适用,则反之亦然吗?
fun bar(): Iterable<Any> { ... }
Run Code Online (Sandbox Code Playgroud)
或者
fun bar(): List<Any> { ... }
Run Code Online (Sandbox Code Playgroud)
是的,是的。正如您所指出的,为了遵守 LSP,重写方法中的参数类型必须是逆变的。对于返回类型来说,反之亦然——这必须是协变的,即与被覆盖的方法中的返回类型具有相同的类型,或更具体的类型。
想想这句口号:“要求不多,承诺不少”。假设超类方法返回一个 Rectangle。可以重写此方法以返回 Square,因为这“承诺更多”,但不能返回 Shape,因为这将“承诺更少”。