我需要创建一个新的类。它的一些功能已经在另一个类中,从域的角度来看,继承它是有意义的。问题是,有一个方法的参数类型必须更为有限,因为LSP(Liskov替换原则)不能覆盖它。
到现在为止还有密码,我可以更改,
为了得到更好的解释,让我举个简单的例子:
我有AnimalShelter
并且需要实现DogShelter
。
class AnimalShelter {
func usefulMethod(...) {}
func take(x: Animal) {}
}
class DogShelter {
var dogMedianCuteness: String = "normal (= very cute)"
func usefulMethod(...) {}
func take(x: Dog) {}
}
解决方案1:子类
如果
DogShelter
是AnimalShelter
的一个子类,那么它将免费获得usefulMethod(...)
,但是继承的方法take(x: Animal)
不能被重写并污染dogholet的API,应该什么都不做或抛出错误。class AnimalShelter {
func usefulMethod(...) {}
func take(x: Animal) {}
}
class DogShelter: AnimalShelter {
var dogMedianCuteness: String = "normal (= very cute)"
func take(x: Dog) {}
}
解决方案2:协议+协议扩展
如果
AnimalShelter
和DogShelter
实现一个协议,从域的角度来看,它并不精确,但是共享代码usefulMethod(...)
可以在协议extension
中实现。protocol UsefulThing {
func usefulMethod(...)
}
extension UsefulThing {
func usefulMethod(...) { ... }
}
class AnimalShelter: UsefulThing {
func take(x: Animal) {}
}
class DogShelter: UsefulThing {
var dogMedianCuteness: String = "normal (= very cute)"
func take(x: Dog) {}
}
解决方案3:泛化,创建另一个超类
问题是
take(x: T)
方法,它在DogShelter
中更为专业化。从AnimalShelter那里拿走它将允许无问题地继承,但是直到现在使用AnimalShelter的所有东西都必须被一个新的子类AnyAnimalShelter: AnimalShelter
替换,这个子类有问题take(x: Animal) {}
class AnimalShelter {
usefulMethod(...) {}
}
class AnyAnimalShelter: AnimalShelter {
take(x: Animal) {}
}
class DogShelter: AnimalShelter {
var dogMedianCuteness: String = "normal (= very cute)"
func take(x: Dog) {}
}
解决方案4:组成
从域的角度来看,继承是有意义的,因此boss认为最好保留它。
因此,我从
AnimalShelter
获得了代码,并被允许更改它,尽管这会引起人们的不满,为什么我要更改运行多年的完美代码。我需要一个关于take(x: Animal)
方法在AnimalShelter
中有缺陷的抽象原因。不仅要有很好的理由反对它,而且要在以后的课堂上避免它。如果我不能更改使用
AnimalShelter
或AnimalShelter
本身的代码,那将是一个真正的问题。问题
有人/我应该如何建模?
最佳答案
您可以使用具有关联类型的协议:
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) {}
}