我需要创建一个新的类。它的一些功能已经在另一个类中,从域的角度来看,继承它是有意义的。问题是,有一个方法的参数类型必须更为有限,因为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:子类
如果DogShelterAnimalShelter的一个子类,那么它将免费获得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:协议+协议扩展
如果AnimalShelterDogShelter实现一个协议,从域的角度来看,它并不精确,但是共享代码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中有缺陷的抽象原因。不仅要有很好的理由反对它,而且要在以后的课堂上避免它。
如果我不能更改使用AnimalShelterAnimalShelter本身的代码,那将是一个真正的问题。
问题
有人/我应该如何建模?

最佳答案

您可以使用具有关联类型的协议:

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) {}
}

10-08 07:14