Я видел множество причин, по которым разработка API с использованием переменных вместо функций является проблематичной, и для меня использование вычисленных свойств кажется обходным решением. Есть веские причины держать переменные экземпляра инкапсулированными. Здесь я создал автомобильный протокол, которому соответствует автомобиль. У этого протокола есть метод доступа, который возвращает объект Chassis. Поскольку Car соответствует ему, подкласс RaceCar может переопределить его и вернуть другой подкласс Chassis. Это позволяет классу Car программировать интерфейс (автомобиль), а класс RaceCar, который знает о RacingChassis, может напрямую обращаться к переменной _racingChassis.
class Chassis {}
class RacingChassis: Chassis {}
protocol Automobile {
func chassis() -> Chassis
}
class Car: Automobile {
private var _chassis: Chassis
init () {
_chassis = Chassis()
}
func chassis() -> Chassis {
return _chassis
}
}
class RaceCar: Car {
private var _racingChassis: RacingChassis
override init () {
_racingChassis = RacingChassis()
super.init()
}
override func chassis() -> Chassis {
return _racingChassis
}
}
Еще один пример того, почему разработка API с использованием переменных не работает, - это когда у вас есть переменные в протоколе. Если вы хотите разбить все функции протокола на расширения, вы можете, за исключением того, что сохраненные свойства не могут быть помещены в расширения и должны быть определены в классе (чтобы это скомпилировалось, вам нужно раскомментировать код в AdaptableViewController и удалите переменную режима из расширения):
protocol Adaptable {
var mode: Int { get set }
func adapt()
}
class AdaptableViewController: UIViewController {
// var mode = 0
}
extension AdaptableViewController: Adaptable {
var mode = 0 // compiler error
func adapt() {
//TODO: add adapt code
}
}
В приведенном выше коде будет ошибка компилятора: «Расширения могут не иметь сохраненных свойств». Вот как вы можете переписать приведенный выше пример, чтобы все в протоколе можно было отделить в расширении, используя вместо этого функции:
protocol Adaptable {
func mode() -> Int
func adapt()
}
class AdaptableViewController: UIViewController {
}
extension AdaptableViewController: Adaptable {
func mode() -> Int {
return 0
}
func adapt() {
// adapt code
}
}
strongсвойством, и я получал ошибку при попытке переопределить его, но, похоже, я пропустил, что он переводится как «неявно развернутый необязательный» (chassis!) в Свифт, такoverride var chassis : Chassis!исправляет.