[英]Swift, classes based on extended protocol don't conform to original protocol
这些协议让我做噩梦。
我正在尝试实现几个符合它们的协议和类,这样我就可以有默认实现,但是通过扩展协议/类可以使用自定义实现。 到目前为止,这就是我所拥有的:
protocol ProtA {
var aProperty: String { get set }
var anotherProperty:String { get set }
func aFunc (anArgument: String) -> String
}
protocol ProtB: ProtA {
var aThirdProperty: String { get set }
}
protocol ProtC {
func doSomething(parameter: Int, with anotherParameter: ProtA)
}
class ClassA: ProtA {
var aProperty: String = "Hello, I'm a String."
var anotherProperty: String = "I'm not the same String."
func aFunc (anArgument: String) -> String {
return anArgument
}
}
class ClassB: ProtB {
var aProperty: String = "Hello, I'm a String."
var anotherProperty: String = "I'm not the same String."
var aThirdProperty: String = "I'm yet another String!"
func aFunc (anArgument: String) -> String {
return anArgument
}
}
class ClassC: ProtC {
func doSomething(parameter: Int, with anotherParameter: ProtA) {
print (anotherParameter.aProperty) // Works fine.
}
}
那么,如果我这样做
class ClassC: ProtC {
func doSomething(parameter: Int, with anotherParameter: ProtA) {
print (anotherParameter.aProperty) // Works fine.
}
}
但是,如果我这样做
class ClassD: ProtC {
func doSomething(parameter: Int, with anotherParameter: ProtA) {
print (anotherParameter.aThirdProperty) // Value of type 'ProtA' has no member 'aThirdProperty'
}
}
而且,如果我这样做
class ClassE: ProtC {
func doSomething(parameter: Int, with anotherParameter: ProtB) {
print (anotherParameter.aThirdProperty) // Type 'ClassE' does not conform to protocol 'ProtC'
}
}
我究竟做错了什么?
从类型继承时,您不能缩小覆盖函数中使用的参数的类型。 这就是您通过将参数从类型ProtA
(更通用的类型)更改为ProtB
(更具体的类型) ProtB
。
这是Liskov 替换原则的结果。 简单地说,子类必须能够(至少)做超类可以做的所有事情。
ProtC
确定所有符合的类型都有一个函数func doSomething(parameter: Int, with anotherParameter: ProtA)
,类型为(Int, ProtA) -> Void)
。
您在ClassE
修改的函数类型为(Int, ProtB) -> Void
。 但是,此函数不能再替代它所覆盖的函数。
假设有可能做你尝试过的事情。 看看会发生什么:
let instanceConformingToProtA: ProtA = ClassA()
let instanceConformingToProtC: ProtC = ClassE()
// This would have to be possible:
instanceConformingToProtC(parameter: 0, amotherParameter: instanceConformingToProtA)
但是, ClassE()
不能将instanceConformingToProtA
作为其第二个参数的有效参数,因为它是ProtA
,而不是必需的ProtB
。
此问题的解决方案完全取决于您要实现的目标。 在继续之前,我需要更多信息。
根据经验,当覆盖继承的成员时:
Car
类型的参数覆盖函数,并将参数类型更改为RaceCar
。 这样做会破坏您的类使用RaceCar
的能力,而 LSP 必须能够做到这一点。Car
类型的参数覆盖函数,并将参数更改为Vehicle
。 这样做可以保留您的类使用“车辆”的能力。Vehicle
的函数覆盖返回类型为Car
的函数。 这样做意味着返回的值比超类保证的“功能更弱”。RaceCar
的函数覆盖返回类型为Car
的函数。 这样做意味着返回的值“更强大”,并且它的作用至少与超类所保证的一样多。没有什么不对的。 您应该确保声明在语义上是一致的。 您应该创建 ProtD,使用 ProtB 参数声明方法,或者解开获取的 ParamA 参数以将其用作 ProtB。
func doSomething(parameter: Int, with anotherParameter: ProtB) {
if let a = anotherParameter as? ProtA {
print (a.aThirdProperty)
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.