Как я могу переопределить функцию с различными унаследованными аргументами (Swift)

#swift #inheritance #overriding #abstract-class #extends

#swift #наследование #переопределение #абстрактный класс #расширяет

Вопрос:

Как переопределить функцию с унаследованным аргументом в Swift?

У меня есть классы:

 class ItemA {
    var valueA: String?
    func setValueA(_ value: String?) {
        valueA = value
    }
}

class ItemB: ItemA {
    var valueB: String?
    func setValueB(_ value: String?) {
        valueB = value
    }
}

// Analog of the abstract class
class ClassA {
    func setValues(_ item: ItemA) {
        item.setValueA("valueA")
        getValues(item) // call getValues from ClassB
    }
    func getValues(_ item: ItemA) {
        abort()
    }
}

class ClassB: ClassA {
    override func setValues(_ item: ItemB) { // item have type itemB, but extends ItemA
        item.setValueB("valueB")
        super.setValues(item)
    }
    override func getValues(_ item: ItemA) {
        let item = item as! ItemB
        let array = [item.valueA, item.valueB]
        print(array)
    }
}
  

Моя цель — получить следующие результаты:

 let itemB = ItemB()
ClassB().setValues(itemB)
// print ["valueA", "valueB"]
  

Я не могу переопределить функцию в классе, потому что типы разные, и в Swift нет наследования типов. Я получаю эту ошибку в setValues(_ item: ItemB) методе из ClassB :

Метод не переопределяет какой-либо метод из своего суперкласса

В Java это может быть реализовано с использованием абстрактного класса и расширяемого типа:

 abstract class ClassA {
    <T extends ItemA> void setValues(T item) {
    item.setValueA("valueA");
        getValues(item);
    }
    abstract void getValues(MainItem item);
}
  

Ответ №1:

Правильный ответ зависит от обобщений:

 class ItemA {
    var valueA: String?
    func setValueA(_ value: String?) {
        valueA = value
    }
}

class ItemB: ItemA {
    var valueB: String?
    func setValueB(_ value: String?) {
        valueB = value
    }
}

// Analog of the abstract class
class ClassA {
    func setValues<T : ItemA>(_ item: T) {
        item.setValueA("valueA")
        getValues(item) // call getValues from ClassB
    }
    func getValues(_ item: ItemA) {
        abort()
    }
}

class ClassB: ClassA {
    override func setValues<T : ItemB>(_ item: T) {
        // item have type itemB, but extends ItemA
        item.setValueB("valueB")
        super.setValues(item)
    }
    override func getValues(_ item: ItemA) {
        let item = item as! ItemB
        let array = [item.valueA, item.valueB]
        print(array)
    }
}
  

Проверьте это! Если вы хотите напечатать необязательные значения, разверните их.

     let itemB = ItemB()
    ClassB().setValues(itemB)
    // print ["valueA", "valueB"]
  

Комментарии:

1. Отлично! Большое вам спасибо!

2. Этот ответ не решает проблему, которую выделяет другой ответ (то, что приведение вашего ClassB к ClassA позволяет вам передать ItemA ему).

3. Это другая задача с другими функциями setValues и getValues . Просто напишите другие методы для ее решения.

Ответ №2:

ClassB.setValues не могу принять аргумент типа ItemB (даже если это подкласс ItemA ), потому что это нарушило бы принцип подстановки Лискова.

ClassB экземпляры должны иметь возможность делать все, что ClassA могут экземпляры. Одним из таких требований является принятие ItemA аргументов для его setValues метода. В противном случае, что произошло бы в этом коде?

 let classAInst: ClassA = ClassB()
classAInstance.setValues(ItemA())
  

Комментарии:

1. Это не решает мою проблему. В этом случае я получу ["valueA"] вместо ["valueA", "valueB"] , поскольку он будет работать только ClassA с ItemA .

2. Вы можете решить проблему с помощью дженериков, а также в java. Я предоставил правильный ответ выше.