首页 > 解决方案 > 如何使用共享代码对更有限的类版本进行建模?

问题描述

我需要创建一个新类。它的一些功能已经在另一个类中,从领域的角度来看,继承它是有意义的。问题是有一种方法的参数类型必须受到更多限制,因为 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:子类

如果DogShelterAnimalShelterthen 的子类,它将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) {}
}

方案二:协议+协议扩展

如果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:组合

从领域的角度来看,继承确实有意义,因此老板认为最好保留。


所以我从那里得到了代码AnimalShelter并且被允许更改它,即使它会引起人们的注意,为什么我会更改运行多年的代码。我需要一个抽象的理由来说明该take(x: Animal)方法在AnimalShelter. 不仅要有充分的理由反对它,还要在以后的课程中避免它。

如果我不能更改使用 AnimalShelterAnimalShelter本身的代码,那将是一个真正的问题。

问题

某人/我应该如何建模?

标签: swiftparametersliskov-substitution-principle

解决方案


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

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

推荐阅读