Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/swift/16.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Swift 如何使用共享代码对类的更有限版本进行建模?_Swift_Parameters_Liskov Substitution Principle - Fatal编程技术网

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

Swift 如何使用共享代码对类的更有限版本进行建模?,swift,parameters,liskov-substitution-principle,Swift,Parameters,Liskov Substitution Principle,我需要创建一个新类。它的一些功能已经在另一个类中,从域的角度来看,从它继承是有意义的。问题在于,有一种方法的参数类型必须更加有限,因为LSP Liskov替换原则,您不能覆盖它 到目前为止,还有一些代码,我可能会更改 为了更好地解释,让我举一个简单的例子: 我有动物收容所,我需要实施狗收容所 解决方案1:子类 如果狗收容所是动物收容所的一个子类,那么它将得到有用的方法。。。免费的,但是继承的方法takex:Animal不能被重写,也不能污染DogHeadder的API,应该什么都不做或者抛出错误

我需要创建一个新类。它的一些功能已经在另一个类中,从域的角度来看,从它继承是有意义的。问题在于,有一种方法的参数类型必须更加有限,因为LSP Liskov替换原则,您不能覆盖它

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

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

我有动物收容所,我需要实施狗收容所

解决方案1:子类 如果狗收容所是动物收容所的一个子类,那么它将得到有用的方法。。。免费的,但是继承的方法takex:Animal不能被重写,也不能污染DogHeadder的API,应该什么都不做或者抛出错误

class AnimalShelter {
    func usefulMethod(...) {}

    func take(x: Animal) {}
}

class DogShelter: AnimalShelter {
    var dogMedianCuteness: String = "normal (= very cute)"

    func take(x: Dog) {}
}
解决方案2:协议+协议扩展 如果AnimalShelter和DogHeadder实现了一个协议,从领域的角度来看,这并不精确,但共享代码是有用的方法。。。可以在协议扩展中实现

解决方案3:泛化,创建另一个超类 问题在于takex:T方法,它在DogHudder中更为专业。将其从AnimalShelter中移除将允许毫无问题地继承,但是到目前为止使用AnimalShelter的所有内容都必须被一个新的子类AnyanAnimalShelter:AnimalShelter替换,该子类有问题的takex:Animal{}

解决方案4:组成 从域的角度来看,继承是有意义的,因此boss认为最好保留继承

所以我从AnimalShelter那里得到了代码,并被允许更改它,尽管这会让人惊讶,为什么我会更改多年来运行良好的代码。我需要一个关于takex的抽象原因:动物方法在AnimalShelter中有缺陷。不仅要有很好的理由反对它,而且要在以后的课堂上避免它

如果我不能更改使用AnimalShelter或AnimalShelter本身的代码,这将是一个真正的问题

问题
某人/我应该如何建模?

清扫者建议的解决方案

class Animal {}
class Dog: Animal {}
当没有任何存储属性时,使用泛型+类扩展和类型约束where子句

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

    func take(x: T) {}
}

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

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

正如您正确识别的,这违反了LSV,所以DogHeader应该与AnimalShelter无关。那么一个允许避难所和避难所等的避难所类呢?@Sweeper对于给定的示例来说,这确实是最好的解决方案。但是可能有一些属性/方法/协议继承只在DogHeadder类中,例如bite方法,那么您将把它们放在哪里?只要它们不是存储属性,即方法和计算属性等都可以,您可以将它们放在扩展中。@Sweeper当然,我在项目中有一个存储属性,这个例子与之相关。将其添加到示例中以反映这一点。也许还有一种方法可以使用泛型,我们必须考虑一下。一个协议避难所,它有一个关联的类型AnimalType,dogheerd和AnimalShelter都符合这个类型呢?你需要在任何地方使用庇护所吗?
class Animal {}
class Dog: Animal {}
class AnimalShelter<T: Animal> {
    func usefulMethod(...) {}

    func take(x: T) {}
}
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) {}
}