Как я могу использовать расширение класса, чтобы переопределить расширение протокола? - PullRequest
0 голосов
/ 27 июня 2018

Допустим, у меня есть цветовая модель:

protocol Color {
    var value: String? { get }
}

class UnknownColor: Color {
    let value: String? = nil
}

class KnownColor: Color {
    let value: String?

    init(value: String? = nil) {
        self.value = value
    }
}

В моем файле вида я добавляю некоторые детали вида в мою модель цвета. Эти детали не зависят от модели, а от вида.

fileprivate extension Color {
    fileprivate var representation: String {
        return self.value!
    }
}

fileprivate extension UnknownColor {
    fileprivate var representation: String {
        return "#000"
    }
}

Теперь, когда я использую свою цветовую модель в файле вида, я ожидаю, что мои UnknownColor s будут представлять себя как "#000", но это не тот случай, когда UnknownColor приводится как Color.

let color1 = KnownColor()
let color2 = KnownColor(value:"#fff")
let color3 = UnknownColor()

color1.representation  // Fatal error  (GOOD)
color2.representation  // "#fff"  (GOOD)
color3.representation  // "#000" (GOOD)

if let color = color3 as? Color {
    color.representation // Fatal error  (BAD, expected "#000")
}

Я хочу избежать явной проверки типов для UnknownColor, поэтому подобное решение не является идеальным:

func colorRepresentation(_ color: Color) {
    if let color = color as? UnknownColor {
        return "#000"
    } else {
        return color.value!
    }
}

Я хочу избежать любых изменений в модели Color любой ценой.

Может быть много реализаций протокола Color, которые хотят использовать Color.representation, поэтому изменение extension Color на extension KnownColor не вариант.

Есть ли способ, которым я могу реструктурировать свой код так, чтобы UnknownColor.representation использовался, когда Color на самом деле UnknownColor?

1 Ответ

0 голосов
/ 27 июня 2018

Я копирую и вставляю ваш код прямо на игровую площадку, и он работает нормально (color3.representation == "# 000").

Расширения находятся в отдельном файле? Если это так, ключевое слово fileprivate сделает их невидимыми для классов.

Для справки, вот весь код, который я поместил на игровую площадку:

protocol Color {
    var value: String? { get }
}

class UnknownColor: Color {
    let value: String? = nil
}

class KnownColor: Color {
    let value: String?

    init(value: String? = nil) {
        self.value = value
    }
}

fileprivate extension Color {
    fileprivate var representation: String {
        return self.value!
    }
}

fileprivate extension UnknownColor {
    fileprivate var representation: String {
        return "#000"
    }
}

let color1 = KnownColor()
let color2 = KnownColor(value:"#fff")
let color3 = UnknownColor()

//color1.representation  // Fatal error  (GOOD)
color2.representation  // "#fff"  (GOOD)
color3.representation  // Fatal error  (BAD, expected "#000")
...