Перенос пункта наследования расширений класса в расширения протокола

У меня была структура VehicleModels с такими классами, как Car, Bike, Plane. В другом фреймворке VehicleInventory мне нужно было распечатать настраиваемые описания (специфичные для второго фреймворка) в таблице. Поэтому я добавил протокол DescriptableVehicle с методом describe(). Затем я добавил расширения протокола для всех транспортных средств, например:

extension Car: DescriptableVehicle {
  func describe() -> String {
    return "Car: \(self.vin)" // returns formatted vehicle number
  }
}

Однако предположения изменились, и теперь я не выставляю конкретные классы из своего каркаса транспортных средств. Вместо этого я выставляю протоколы типа CarProtocol, BikeProtocol, чтобы в целом у меня была та же информация.

Проблема в том, что я больше не могу использовать расширения протокола (или, по крайней мере, не в такой форме), потому что расширение протокола в противоположность расширению класса не может иметь пункт наследования .

Любая идея, как я могу решить проблему, чтобы не сильно изменять свои привычки? Первоначально я думал, что пара where пунктов в протоколах плюс пара приведения сделают дело, однако без доступа к классам это не помогает. Я также пробовал адаптеры и стирание текста, но либо я использую его плохо, либо он служит другой цели.

Для иллюстрации проблемы я подготовил репозиторий: https://github.com/wedkarz/SwiftProtocolExtensionsProblem

Есть две детские площадки. V1 — это то, что у меня было раньше, и оно работало. V2 содержит то, что у меня есть сейчас, и то, что я пытаюсь заставить работать.

В реальной жизни класс PrivateFramework представляет собой отдельный фреймворк и протоколы: VehicleProtocol, CarProtocol, BikeProtocol, PlaneProtocol являются его частью, но DescriptableVehicle не является частью PrivateFramework, поэтому его нельзя использовать внутри. Пример иллюстрирует проблему с доступом к конкретным типам и проблему с их расширениями.

Вы можете видеть, что расширения закомментированы, потому что я больше не могу их использовать. Цель состоит в том, чтобы коллекция [VehicleProtocol] печатала свое содержимое так же, как она работала ранее.


person Fishman    schedule 22.11.2017    source источник
comment
Вы должны предоставить больше кода, совершенно неясно, что у вас есть и в чем проблема с ним.   -  person Alexander    schedule 22.11.2017
comment
Хорошо, я буду. Между тем, не могли бы вы выделить то, что неясно?   -  person Fishman    schedule 22.11.2017
comment
Я просто не могу представить, что у вас есть сейчас, какова ваша цель и что доставляет вам неприятности. Просмотр MVE кода поможет   -  person Alexander    schedule 22.11.2017
comment
Я подготовил репозиторий, который как-то иллюстрирует мою проблему. github.com/wedkarz/SwiftProtocolExtensionsProblem, дайте мне знать, если мне что-то неясно   -  person Fishman    schedule 23.11.2017


Ответы (1)


Отвечает ли это на ваш вопрос?

class PrivateFramework {
    private class AbstractVehicle: VehicleProtocol {
        var name: String { return "Abstract vehicle name" }
    }

    private class Car: AbstractVehicle, CarProtocol {
        override var name: String { return "Car vehicle name" }
        let vin: String = "ABCDEFGH VIN"
    }

    private class Bike: AbstractVehicle, BikeProtocol {
        override var name: String { return "Bike vehicle name" }
        let saddle: String = "Comforable saddle name"
    }

    private class Plane: AbstractVehicle, PlaneProtocol {
        override var name: String { return "Plane vehicle name" }
        let numberOfEngines: Int = 4
    }

    func produceVehicles() -> [DescriptableVehicle] {
        let car = Car()
        let bike = Bike()
        let plane = Plane()
        return [car, bike, plane]
    }
}

protocol VehicleProtocol {
    var name: String { get }
}

protocol DescriptableVehicle: VehicleProtocol {
    func describe() -> String
}



protocol CarProtocol: DescriptableVehicle {
    var vin: String { get }
}

protocol BikeProtocol: DescriptableVehicle {
    var saddle: String { get }
}

protocol PlaneProtocol: DescriptableVehicle {
    var numberOfEngines: Int { get }
}




extension DescriptableVehicle where Self: CarProtocol {
    func describe() -> String { return "Car, \(self.name), \(self.vin)" }
}

extension DescriptableVehicle where Self: BikeProtocol {
    func describe() -> String { return "Bike, \(self.name), \(self.saddle)" }
}

extension DescriptableVehicle where Self: PlaneProtocol {
    func describe() -> String { return "Plane, \(self.name), \(self.numberOfEngines)" }
}

let vehicles: [DescriptableVehicle] = PrivateFramework().produceVehicles()

vehicles.forEach { print($0.describe()) }
person Alexander    schedule 23.11.2017
comment
Нет. Протокол DescriptableVehicle не является частью Private framework, поэтому вы не можете использовать его внутри, как func produceVehicles() -> [DescriptableVehicle]. Это другая функциональность фреймворка. Мой пример немного упрощен, но я описал правила. - person Fishman; 23.11.2017
comment
@Fishman Ну, тогда вам нужно вернуть [VehicleProtocol] и привести содержимое, чтобы получить те экземпляры, которые являются VehicleProtocol, но также и DescriptableVehicle - person Alexander; 23.11.2017
comment
Но вот в чем загвоздка, вы получите ноль, когда попытаетесь разыграть. - person Fishman; 24.11.2017
comment
@Fishman Конечно, если бы класс изначально не соответствовал DescriptableVehicle, и никто не расширил его для соответствия, чего бы вы ожидали? Вы попытаетесь вызвать метод DescriptableVehicle для типа, для которого он не определен. - person Alexander; 24.11.2017
comment
Отсюда и проблема. Первоначально я мог расширять конкретные типы. Теперь у меня есть интерфейсы. Как с этим бороться (не меняя Private framework) - как преобразить мои бывшие расширения классов, чтобы не пришлось все переписывать. - person Fishman; 24.11.2017
comment
@Fishman Итак, CarProtocol/BikeProtocol/PlaneProtocol не являются частью PrivateFramework, но фреймворк имеет к ним доступ, но DescriptableVehicle не является частью фреймворка, и фреймворк не имеет к нему доступа? - person Alexander; 24.11.2017
comment
:/ Это именно то, что я описал в выпуске. Протокол Car/Bike/Plane/VehicleProtocol является частью частной структуры, общедоступной снаружи. «DescriptableVehicle» не является частью фреймворка. - person Fishman; 24.11.2017
comment
Давайте продолжим обсуждение в чате. - person Alexander; 24.11.2017