Swift 如何使用共享代码对类的更有限版本进行建模?
我需要创建一个新类。它的一些功能已经在另一个类中,从域的角度来看,从它继承是有意义的。问题在于,有一种方法的参数类型必须更加有限,因为LSP Liskov替换原则,您不能覆盖它 到目前为止,还有一些代码,我可能会更改 为了更好地解释,让我举一个简单的例子: 我有动物收容所,我需要实施狗收容所 解决方案1:子类 如果狗收容所是动物收容所的一个子类,那么它将得到有用的方法。。。免费的,但是继承的方法takex:Animal不能被重写,也不能污染DogHeadder的API,应该什么都不做或者抛出错误Swift 如何使用共享代码对类的更有限版本进行建模?,swift,parameters,liskov-substitution-principle,Swift,Parameters,Liskov Substitution Principle,我需要创建一个新类。它的一些功能已经在另一个类中,从域的角度来看,从它继承是有意义的。问题在于,有一种方法的参数类型必须更加有限,因为LSP Liskov替换原则,您不能覆盖它 到目前为止,还有一些代码,我可能会更改 为了更好地解释,让我举一个简单的例子: 我有动物收容所,我需要实施狗收容所 解决方案1:子类 如果狗收容所是动物收容所的一个子类,那么它将得到有用的方法。。。免费的,但是继承的方法takex:Animal不能被重写,也不能污染DogHeadder的API,应该什么都不做或者抛出错误
class AnimalShelter {
func usefulMethod(...) {}
func take(x: Animal) {}
}
class DogShelter: AnimalShelter {
var dogMedianCuteness: String = "normal (= very cute)"
func take(x: Dog) {}
}
解决方案2:协议+协议扩展
如果AnimalShelter和DogHeadder实现了一个协议,从领域的角度来看,这并不精确,但共享代码是有用的方法。。。可以在协议扩展中实现
解决方案3:泛化,创建另一个超类
问题在于takex:T方法,它在DogHudder中更为专业。将其从AnimalShelter中移除将允许毫无问题地继承,但是到目前为止使用AnimalShelter的所有内容都必须被一个新的子类AnyanAnimalShelter:AnimalShelter替换,该子类有问题的takex:Animal{}
解决方案4:组成
从域的角度来看,继承是有意义的,因此boss认为最好保留继承
所以我从AnimalShelter那里得到了代码,并被允许更改它,尽管这会让人惊讶,为什么我会更改多年来运行良好的代码。我需要一个关于takex的抽象原因:动物方法在AnimalShelter中有缺陷。不仅要有很好的理由反对它,而且要在以后的课堂上避免它
如果我不能更改使用AnimalShelter或AnimalShelter本身的代码,这将是一个真正的问题
问题
某人/我应该如何建模?清扫者建议的解决方案
class Animal {}
class Dog: Animal {}
当没有任何存储属性时,使用泛型+类扩展和类型约束where子句
class AnimalShelter<T: Animal> {
func usefulMethod(...) {}
func take(x: T) {}
}
您可以使用具有关联类型的协议:
protocol Shelter {
associatedtype AnimalType
func take(x: AnimalType)
}
extension Shelter {
func usefulMethod(...)
}
class AnimalShelter : Shelter {
typealias AnimalType = Animal
func take(x: Animal) { ... }
}
class DogShelter : Shelter {
typealias AnimalType = Dog
var dogMedianCuteness: String = "normal (= very cute)"
func take(x: Dog) {}
}
正如您正确识别的,这违反了LSV,所以DogHeader应该与AnimalShelter无关。那么一个允许避难所和避难所等的避难所类呢?@Sweeper对于给定的示例来说,这确实是最好的解决方案。但是可能有一些属性/方法/协议继承只在DogHeadder类中,例如bite方法,那么您将把它们放在哪里?只要它们不是存储属性,即方法和计算属性等都可以,您可以将它们放在扩展中。@Sweeper当然,我在项目中有一个存储属性,这个例子与之相关。将其添加到示例中以反映这一点。也许还有一种方法可以使用泛型,我们必须考虑一下。一个协议避难所,它有一个关联的类型AnimalType,dogheerd和AnimalShelter都符合这个类型呢?你需要在任何地方使用庇护所吗?
class Animal {}
class Dog: Animal {}
class AnimalShelter<T: Animal> {
func usefulMethod(...) {}
func take(x: T) {}
}
protocol Shelter {
var animalType: Any.Type { get }
func usefulMethod() -> String
}
extension Shelter {
func usefulMethod() -> String {
return "useful"
}
}
class AnimalShelter: Shelter {
let animalType: Any.Type = Animal.self
func take(x: animalType) {}
}
class DogShelter: Shelter {
let animalType: Any.Type = Dog.self
var dogMedianCuteness: String = "normal (= very cute)"
func take(x: animalType) {}
}
protocol Shelter {
associatedtype AnimalType
func take(x: AnimalType)
}
extension Shelter {
func usefulMethod(...)
}
class AnimalShelter : Shelter {
typealias AnimalType = Animal
func take(x: Animal) { ... }
}
class DogShelter : Shelter {
typealias AnimalType = Dog
var dogMedianCuteness: String = "normal (= very cute)"
func take(x: Dog) {}
}