Ограничить расширения для типа в Swift?

У меня есть определенный класс в Swift, который я хотел бы ограничить создание расширений. Я пытался добавить final ключевое слово, но оно не ограничивает расширения:

final class MyTest {
    func testFunc() {}
}

extension MyTest {
    func testFunc2() {}
}

let test = MyTest()
test.testFunc2()

Это возможно?

1 ответ

Решение

Вы не можете запретить кому-либо добавлять расширение в ваш класс. Как будто вы не можете помешать другому разработчику написать функцию, которая использует ваш класс.

final Модификатор только предотвращает создание подклассов. Другие разработчики всегда смогут добавить расширения.

Это действительно проблема?

ИМХО это не так.

Давайте посмотрим на этот класс

final class Person {
    private let name: String
    func tellName() -> String { return "I am \(name)" }
    init(name: String) {
        self.name = name
    }
}

Теперь другой разработчик может записать (в другой исходный файл) эту функцию

func presentAndTellName(person: Person) {
    print("Hello everybody! \(person.tellName())")
}

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

Другой разработчик не может использовать private свойства / методы нашего класса (если он не имеет доступа к нашему исходному файлу). Он также не может добавить свойства Person потому что это класс, помеченный как final так что подклассы - это пределы. Он может писать только код, который его использует.

У нас все хорошо с этим верно?

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

Поэтому мы используем расширения для преобразования этого

func presentAndTellName(person: Person) {
    print("Hello everybody! \(person.tellName())")
}

в это

extension Person {
    func presentAndTellName() {
        print("Hello everybody! \(self.tellName())")
    }
}

Это всего лишь способ написать ту же логику и сделать ее доступной в синтаксисе ООП.

Теперь вместо того, чтобы писать это

presentAndTellName(person)

мы можем написать это

person.presentAndTellName()

Сделайте ваши вещи частными

Итак, как вы можете защитить некоторые из ваших (/struct) логики и данных от расширений? С тем же механизмом, который вы используете для защиты этого материала от функций, внешних по отношению к вашему исходному файлу, просто отметьте их private, Таким образом, другие разработчики не смогут использовать их в своих расширениях.

Давайте снова посмотрим на наш класс Person.

class Person {
    private let name: String
    func tellName() -> String { return "I am \(name)" }
    init(name: String) {
        self.name = name
    }
}

name собственность является частной, поэтому нет никакой возможности, и внешняя функция или расширение смогут получить к ней прямой доступ.

Подождите, а как насчет протоколов?

Хорошо, это, пожалуй, единственная вещь, где расширения предлагают нечто большее, чем лучший синтаксис.

Infact, учитывая этот протокол

protocol Runner {
    func run()
}

мы можем соответствовать этому классу мы не владеем

extension Person: Runner {
    func run() { print("") }
}
Другие вопросы по тегам