swift - 如何使用共享代码对更有限的类版本进行建模?
问题描述
我需要创建一个新类。它的一些功能已经在另一个类中,从领域的角度来看,继承它是有意义的。问题是有一种方法的参数类型必须受到更多限制,因为 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
then 的子类,它将usefulMethod(...)
免费获得,但继承的方法take(x: Animal)
不能被覆盖并污染 DogShelter 的 API,应该什么都不做或抛出错误。
class AnimalShelter {
func usefulMethod(...) {}
func take(x: Animal) {}
}
class DogShelter: AnimalShelter {
var dogMedianCuteness: String = "normal (= very cute)"
func take(x: Dog) {}
}
方案二:协议+协议扩展
如果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:组合
从领域的角度来看,继承确实有意义,因此老板认为最好保留。
所以我从那里得到了代码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) {}
}
推荐阅读
- javascript - 无法使用 Javascript 向 json 对象添加新的键和值
- java - 在java中使用命令行参数时没有得到正确的输出
- python-3.x - 使用 python 3.8 安装 scikit-learn 19.1 时出错
- python - Python:Tkinter:动态创建标签
- dart - Dart:这些方括号在构造函数中的作用是什么?
- javascript - 无法从 axios 请求访问上传的文件到 laravel
- javascript - GatsbyJS 中的 Socket IO 客户端不起作用
- wayland - 两个简单的韦斯顿示例有什么区别?
- awk - 如何在unix文件中查找两个时间戳之间的行
- instagram - 过滤器在 Spark AR 模拟器中有效,但在应用程序中无效?