泛型类和继承

3

我有一个模型对象:

class Animal {
// ...
}

以及子类:

class Dog: Animal {
// ...
}

class Cat: Animal {
// ...
}

我创建了一个通用类。

class AnimalController<T: Animal> {
      var animal: T? 
      func feed(animal: T) {
          let food = Food(T.self)
          animal.feed(food)
      }
}

以下是问题所在:

class MainViewController: UIViewController {
      var controller: AnimalController<Animal>?

    // MARK: - Lifecycle

    override func viewDidLoad() {
        super.viewDidLoad()

        // I want control a dog
        self.controller = AnimalController<Dog>()  // Error

        // I want control a cat
        self.controller = AnimalController<Cat>()  // Error
    }
}

我该如何创建一个适用于狗和猫的通用类?谢谢!

更新:Hamish给了我解决方案,链接了其他两篇文章。

我有模型对象:

class Animal {
// ...
}

以及其子类:

class Dog: Animal {
// ...
}

class Cat: Animal {
// ...
}

此外,我已经创建了一个通用类。
class AnimalController<T> {
    var type: T

    init(type: T) {
        self.type = type
    }

    func feed() {
        if type is Animal.Type {
            let food = Food(type as! Animal.Type)
            animal.feed(food)
        }
    }
}

现在它可以正常工作:
class MainViewController: UIViewController {
      var controller: AnimalController<Animal>?

    // MARK: - Lifecycle

    override func viewDidLoad() {
        super.viewDidLoad()

        // I want control a dog
        self.controller = AnimalController<Dog>()  // Works!
        self.controller = AnimalController<Cat>()  // Works!
    }
}

你的类不是很通用:-) 我建议你阅读苹果文档中关于泛型的章节。 - user3441734
拼写错误。抱歉。已编辑。 - torcelly
1
问题在于泛型是不变的 - 可以参考 https://dev59.com/w1gQ5IYBdhLWcg3w9Ygb 和 https://dev59.com/O5nga4cB1Zd3GeqPWEWm - Hamish
你编辑后的代码不可能工作——考虑一下如果你能够将AnimalController<Dog>赋值给AnimalController<Animal>。然后你可以说controller?.feed(animal: Cat())。现在你刚刚把狗食喂给了猫。 - Hamish
谢谢Hamish。我已经阅读了链接,得到了解决方案。我编辑了我的问题并添加了答案。 - torcelly
3个回答

0

看起来应该使用继承而不是泛型。

class AnimalController {
    // basic animal control tasks
}


class CatController: AnimalController {
    // specialized controller just for cats
}
class DogController: AnimalController {
    // ...
}

然后你可以直接写

class MainViewController: UIViewController {
    var animalController: AnimalController

    override func viewDidLoad() {
        super.viewDidLoad()

        // I want control a dog
        self.controller = DogController()

        // I want control a cat
        self.controller = CatController()
    }
}

使用泛型可能会在这种情况下导致问题,因为Swift编译器会解析泛型类型并将其替换为具体类型(除非您使整个视图控制器都是泛型,但这与界面构建器不兼容)。


在控制器中,猫和狗之间没有区别。使用您的代码将是相同的,我们有重复的代码。不同之处在于模型。显然,猫和狗具有不同的属性。谢谢。 - torcelly
如果是这种情况,你只需要动物控制器,而不需要两个子类。其余部分保持不变。 - Palle

0
在你的例子中,没有必要将AnimalController变成一个泛型类。它可以简单地拥有适用于Animals的方法,并且通过继承,这些方法将适用于DogCat
class Animals {
    // ...
}

class Dog: Animals {
    // ...
}

class Cat: Animals {
    // ...
}

class AnimalController {
    // methods to control any kind of animals
    var animal: Animals? // Will take both cats and dogs
    func feed(animal: Animals) {
        // Will take both cats and dogs
    }
}

class MainViewController: UIViewController {
    var controller: AnimalController?

    // MARK: - Lifecycle

    override func viewDidLoad() {
        super.viewDidLoad()

        // I want control a dog or a cat
        self.controller = AnimalController()

        let cat = Cat()
        controller?.animal = cat
        controller?.feed(animal: cat)

        let dog = Dog()
        controller?.animal = dog
        controller?.feed(animal: dog)
    }
}

(已更新)

即使经过您的编辑,我仍然认为不需要使用泛型:

class Animal {
    // ...
    func feed(_ food: Food){
        // feed the animal or maybe throw an error
        // if subclasses must implement
    }
}

class Dog: Animal {
    // ...
    override func feed(_ food: Food) {
        // feed a cat
    }
}

class Cat: Animal {
    // ...
    override func feed(_ food: Food) {
        // feed a dog
    }
}

class Food {
    init(_ animalType: Animal.Type) {
        // Make food
    }
}

class AnimalController {
    // methods to control any kind of animals
    var animal: Animal? // Will take both cats and dogs
    func feed(animal: Animal) {
        // Will take both cats and dogs
        let food = Food(type(of: animal))
        animal.feed(food)
    }
}

class MainViewController: UIViewController {
    var controller: AnimalController?

    // MARK: - Lifecycle

    override func viewDidLoad() {
        super.viewDidLoad()

        // I want control a dog or a cat
        self.controller = AnimalController()

        let cat = Cat()
        controller?.animal = cat
        controller?.feed(animal: cat)

        let dog = Dog()
        controller?.animal = dog
        controller?.feed(animal: dog)
    }
}

首先,感谢您的回答。这很有道理,但是在我的原始代码中,猫和狗之间的“feed”方法必须不同。我已经在我的说明中添加了这种方法,以更清楚地暴露问题。原始方法使用了Realm对象类及其模式,但我不想通过添加许多代码来使问题变得复杂而无必要。 - torcelly
猫和狗之间的区别仅在于算法中发送给其他对象的参数Cat.self或Dog.self。如果我重写这个方法,将会复制很多代码行。 - torcelly

0

Swift 是一种强类型语言。您已经声明了属性 controller,并且不能更改其类型,但这完全没问题,因为 Swift 支持泛型编程范式,允许您将对象保存在具有共同超类的属性中。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接