Функції Swift проти обчислених властивостей


26

Скажіть, у мене клас Eventтакий:

class Event {
    private var attendees: [Person] = []

    // Case 1
    //*******
    // Should I use a func…
    func countOfAttendees() -> Int {
        return attendees.count
    }

    // …or a var
    var countOfAttendees: Int {
        return attendees.count
    }

    // Case 2
    //*******
    // Should I use a func…
    func countOfPaidAttendees() -> Int {
        return attendees.filter({$0.hasPaid}).count
    }

    // …or a var
    var countOfPaidAttendees: Int {
        return attendees.filter({$0.hasPaid}).count
    }
}

Чи найкраще застосовувати функції або обчислювані властивості у двох зазначених вище випадках?


2
stackoverflow.com/questions/24035276/… ... Коротше кажучи: "Нехай ваші функції будуть функціями, а ваші властивості - властивостями."
Роберт Харві

Відповіді:


14

Дотримуйтесь принципу єдиного доступу ,

Усі послуги, пропоновані модулем, повинні бути доступні через єдину нотацію, яка не зраджує, чи реалізована вона через зберігання чи за допомогою обчислень

Для мене це означає, що я не пишу функцій, які не беруть аргументів і не повертають значення. Я завжди використовую обчислювані властивості. Таким чином, якщо пізніше я вирішу змінити обчислену властивість на збережену власність, я можу це зробити, не маючи бажання видаляти паролі скрізь у моєму додатку та не маючи окремого методу "getter", який просто повертає значення збереженого майно, яке IMHO здається досить марнотратним.

І якщо я поміняю збережену властивість на обчислену, мені не доведеться додавати паролі до кінця, а також всюди, де вона використовується в додатку.


Спочатку я пішов з відповіддю на складність @ Антона, але на практиці зрозумів, що саме так я це роблю ... за замовчуванням властивості.
Ешлі Міллс

17

Я б сказав, що це залежить від складності обчислення та частоти використання.

  • Якщо це O(1)/ *, тоді використовуйте обчислену властивість.
  • Якщо це O(N)+/ rare-use, тоді використовуйте функцію.
  • Якщо це O(N)+/ frequent-use, подумайте, чи в майбутньому ви можете вирішити використовувати кешування чи інші "розумні" методи, щоб компенсувати складність, якщо "так", то використовуйте властивість, якщо "ні-ні-ні, це просто важко", тоді використовуйте функцію .

2
Смішно, як я почав це робити, використовуючи ті ж міркування. Якщо ви "можете" створити таке враження, що воно є власністю, навіть якщо вам доведеться зробити легку обробку, доки вона не змінить об'єкт, зробіть це власністю.
Продаж Дільсона

9

Нещодавно я почав вивчати Котлін, і вони мають велику евристику щодо використання обчислених властивостей:

Функції та Властивості

У деяких випадках функції без аргументів можуть бути взаємозамінними з властивостями лише для читання. Хоча семантика схожа, є деякі стилістичні умовності щодо того, коли віддати перевагу одній іншій.

Віддайте перевагу властивості над функцією, коли алгоритм лежить в основі:

  • не кидає
  • має складність O (1)
  • дешево обчислити (або погашено в першому циклі)
  • повертає той самий результат для викликів

- https://kotlinlang.org/docs/reference/coding-conventions.html


"Не кидає" також важливий для Свіфта, оскільки властивості не можуть кинути (поки?)
alejandromp

"має складність O (1)" видалено з документації
Махмуд Шаход

7

У Swift функції без параметрів та обчислених властивостей мають майже однакові можливості (може бути різниця, що функція без параметра також є закриттям, а обчислена властивість - ні).

Різниця семантично. Якщо ваш код виконує дію і повертає, наприклад, опис результату цієї дії, я б використовував функцію. Якщо ваш код обчислює властивість, але з точки зору користувача, це могла бути збережена власність, або, можливо, збережена власність, для якої потрібно спочатку оновити якесь кешоване значення, то я б використовував обчислену властивість.

Велика різниця: що станеться, якщо ви двічі викликаєте функцію чи обчислену властивість? Для обчисленої властивості я очікую, що x = властивість; y = властивість має точно таку саму поведінку, як x = властивість; y = x, за винятком того, що він може працювати трохи менше. Щодо функцій, я не здивувався б, якби поведінка була іншою.


4

Використовуйте countOfAttendeesі countOfPaidAttendees().


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

Чим відрізняється функція?

  • Семантично змінна - стан, функція - дія.
  • Функція регулює доступ до приватного сховища. Обчислена змінна може зробити те ж саме і більш компактним способом. Приклад .
  • Обчислена змінна може бути використана з KVO, передана як #keypath і має засоби для спостереження: willSet, didSet.

Ви повинні використовувати змінну, коли

  • це не кидає
  • він повертає просту властивість
  • він не має побічного ефекту або дієслова в його імені
  • це O (1), тобто він не несе значних витрат. У вашому прикладі це буде O (n).
  • це безсильно. Кілька однакових викликів повертають одне і те ж значення або встановлюють об'єкт в один і той же стан.

Нерелевантні причини віддати перевагу змінній над функцією

  • Обчислена змінна врятує вас від набору тексту (). Однак ясність важливіша, ніж стислість, тому це слабкий аргумент.
  • Змінна лише для читання може бути замінена як читання / запис. Функція вказує, що вона завжди лише для читання. Однак Apple використовує властивості для змінних лише для читання, таких як array.count. Коли ви сумніваєтесь, домагайтесь узгодженості з платформою.

Ресурси

Від  WWDC 2014 - 204 Що нового в какао  > 24:40 Коли використовувати властивість @

Використовуйте властивість для всього, що стосується значення або стану об'єкта або його відношення до інших об'єктів. Погані кандидати:

  • Методи, які виконують такі дії: завантаження, розбір, переключення,…. Вони мають дієслова в його назві.
  • Генератори: init, копія, перерахування,…. Ці методи не є безсильними.
  • Методи, які змінюють стан: nextObject.

Від  стилю Swift від Еріки Садун  > Обчислені властивості проти методів

Властивість виражає властиву якості екземпляра, тоді як метод виконує дію.

  • Методи мають параметри; властивості не мають. Віддайте перевагу методам будь-якого дзвінка з побічними ефектами. Якщо метод робить щось (наприклад, він завантажує, аналізує, перемикає чи друкує) або має назву дієслова, він не повинен бути властивістю.
  • Віддайте перевагу властивостям для простих значень, які ви можете отримати та / або встановити.
  • Властивості повинні виражати смислову властиву якість екземпляра типу.
  • Властивості дозволяють додавати спостерігачів через willSet та didSet. На відміну від збережених властивостей примірника, властивостям збереженого типу завжди має бути задане значення за замовчуванням.

З умов  кодування Котліна> функції та властивості . Дивіться відповідь Даниїла вище .

Інші ресурси без відповідної інформації:


3

Я б використовував func. Об'єктно-орієнтоване програмування працює прекрасно без обчислених властивостей. Оскільки ви отримуєте назад значення, яке було обчислено / відфільтровано, деякі можуть стверджувати, що обчислена властивість вважається правильною. Але ось моя скарга, якщо ви зробите це, то читабельність вражає, оскільки це відчуває як цінність.

У цьому контексті не було б сенсу намагатися призначити обчислене значення (і, на щастя, IDE допомагає нам уникнути цього), але що робити, якщо я спробую призначити щось обчислене, але схоже на значення?

event.countOfAttendees = 0; // not possible

Використовуючи функцію, абонент знає, що ви не маєте прямого значення зі значенням:

event.countOfAttendees()

Я думаю, що якщо його поведінковий об'єкт, він повинен виглядати так, як він поводиться, а не схожий на структуру даних. Якщо ваш об’єкт німий і не має жодної поведінки, то навіщо намагатися інкапсулювати його? У такому випадку ви можете просто мати присутніх публічними

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.