如何使用共享代码对 class 的更有限版本进行建模?

How to model a more limited version of class with shared code?

我需要创建一个新的 class。它的一些功能已经在另一个 class 中,从领域的角度来看,继承它是有意义的。问题是有一个方法必须在它的参数类型上有更多的限制,因为 LSP (Liskov substitution principle) 你不能覆盖它。

到目前为止有代码,我可能会更改,

为了更好的解释让我举一个简单的例子:

我有 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:子class

如果DogShelterAnimalShelter的子class那么它将免费得到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:泛化,创建另一个超级class

问题出在 take(x: T) 方法上,它在 DogShelter 中更为专业。将它从 AnimalShelter 中移除将允许继承而不会出现问题,但是到目前为止使用 AnimalShelter 的所有内容都必须由一个新的 subclass 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 中有缺陷的抽象原因。不仅要有充分的理由反对它,而且还要在将来避免它 classes.

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

问题

someone/I 应该如何建模?

Sweeper 建议的解决方案。

class Animal {}
class Dog: Animal {}

当没有任何存储属性时,使用泛型 + class 带有类型约束(where 子句)的扩展。

class AnimalShelter<T: Animal> {
    func usefulMethod(...) {}

    func take(x: T) {}
}

否则使用解决方案 2:协议、协议扩展并向协议添加关联类型,并在每个 class 中添加相应的类型限制。

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