Funkcje szybkie a właściwości obliczone

26

Powiedz, że mam klasę Eventw następujący sposób:

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
    }
}

Czy najlepszą praktyką jest używanie funkcji lub obliczonych właściwości w 2 przypadkach wskazanych powyżej?

Ashley Mills
źródło
2
stackoverflow.com/questions/24035276/ ... ... Krótko mówiąc: „Niech funkcje będą funkcjami, a właściwości właściwościami”.
Robert Harvey

Odpowiedzi:

14

Przestrzegaj zasady jednolitego dostępu ,

Wszystkie usługi oferowane przez moduł powinny być dostępne za pomocą jednolitej notacji, która nie zdradza, czy są one realizowane za pomocą pamięci czy obliczeń

Dla mnie oznacza to, że nie piszę funkcji, które nie przyjmują argumentów i nie zwracają wartości. Zawsze używam obliczonych właściwości. W ten sposób, jeśli później zdecyduję się zmienić właściwość obliczoną na właściwość przechowywaną, mogę to zrobić bez potrzeby usuwania parens wszędzie w mojej aplikacji i bez osobnej metody „getter”, która po prostu zwraca wartość przechowywanej nieruchomość, która wydaje się dość marnotrawstwem IMHO.

A jeśli zmienię przechowywaną właściwość na obliczoną, nie muszę dodawać parens na jej końcu i wszędzie tam, gdzie jest używana w aplikacji.

Daniel T.
źródło
Początkowo korzystałem z odpowiedzi złożoności @ Antona, ale w praktyce zdałem sobie sprawę, że tak to robię… właściwości domyślnie.
Ashley Mills,
17

Powiedziałbym, że zależy to od złożoności obliczeń w zależności od częstotliwości użytkowania.

  • Jeśli jest to O(1)/ *, użyj właściwości obliczeniowej.
  • Jeśli to O(N)+/ rare-use, użyj funkcji.
  • Jeśli jest O(N)+/ frequent-use, zastanów się, czy w przyszłości możesz zdecydować się na użycie buforowania lub innych „inteligentnych” technik w celu skompensowania złożoności, jeśli „tak”, użyj właściwości, jeśli „nie-nie-nie, to jest po prostu ciężkie”, użyj funkcji .
courteouselk
źródło
2
Zabawne, jak zacząłem to robić z tego samego powodu. Jeśli „możesz” sprawiać wrażenie bycia właściwością, nawet jeśli musisz wykonać lekkie przetwarzanie, o ile nie zmienia on obiektu, uczyń go właściwością.
Dielson Sales
9

Niedawno zacząłem uczyć się Kotlin i mają świetną heurystykę na temat tego, kiedy użyć obliczonych właściwości:

Funkcje a właściwości

W niektórych przypadkach funkcje bez argumentów mogą być wymienne z właściwościami tylko do odczytu. Chociaż semantyka jest podobna, istnieją pewne konwencje stylistyczne dotyczące tego, kiedy preferować jeden od drugiego.

Preferuj właściwość zamiast funkcji, gdy podstawowy algorytm:

  • nie rzuca
  • ma złożoność O (1)
  • jest tani do obliczenia (lub cashhed przy pierwszym uruchomieniu)
  • zwraca ten sam wynik w stosunku do wywołań

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

Daniel T.
źródło
„Nie rzuca” jest również ważne dla Swift, ponieważ właściwości nie mogą (jeszcze?) Rzucać
alejandromp
„ma złożoność O (1)” usunięto z dokumentacji
Mahmoud Shahoud
7

W Swift funkcje bez parametrów i właściwości obliczeniowych mają prawie takie same możliwości (może istnieć różnica, że ​​funkcja bez parametru jest również zamknięciem, podczas gdy właściwość obliczona nie jest).

Różnica jest semantyczna. Jeśli twój kod wykonuje akcję i zwraca na przykład opis wyniku tej akcji, użyłbym funkcji. Jeśli kod oblicza właściwość, ale z punktu widzenia użytkownika może to być właściwość przechowywana, a może właściwość przechowywana, która wymaga najpierw aktualizacji pewnej wartości z pamięci podręcznej, wówczas użyłbym właściwości obliczonej.

Duża różnica: co się stanie, jeśli wywołasz funkcję lub obliczoną właściwość dwukrotnie? W przypadku obliczonej właściwości oczekuję, że x = właściwość; y = właściwość ma dokładnie takie samo zachowanie jak x = właściwość; y = x, ale może działać trochę wolniej. W przypadku funkcji nie byłbym zaskoczony, gdyby zachowanie było inne.

gnasher729
źródło
4

Użyj countOfAttendeesi countOfPaidAttendees().


Obliczona zmienna to taka, która zwraca obliczoną wartość za każdym razem, gdy jest dostępna. Oznacza to, że nie przechowuje wartości. Wewnętrznie jest implementowany jako funkcja.

Jaka jest różnica z funkcją?

  • Semantycznie zmienna jest stanem, funkcja jest działaniem.
  • Funkcja reguluje dostęp do prywatnego przechowywania. Obliczona zmienna może zrobić to samo w bardziej zwarty sposób. Przykład .
  • Obliczona zmienna może być używana z KVO, przekazywana jako #keypath, i posiada udogodnienia do obserwowania: willSet, didSet.

Powinieneś użyć zmiennej, kiedy

  • nie rzuca
  • zwraca prostą właściwość
  • w nazwie nie ma skutków ubocznych ani czasownika
  • jest to O (1), co oznacza, że ​​nie ponosi znaczących kosztów. W twoim przykładzie będzie to O (n).
  • jest idempotentny. Wiele identycznych wywołań zwraca tę samą wartość lub ustawia obiekt w tym samym stanie.

Nieistotne powody, dla których preferuje się zmienną nad funkcją

  • Obliczona zmienna pozwala uniknąć wpisywania (). Jednak jasność jest ważniejsza niż zwięzłość, więc jest to słaby argument.
  • Zmienna tylko do odczytu może zostać nadpisana jako odczyt / zapis. Funkcja wskazuje, że zawsze jest tylko do odczytu. Jednak Apple używa właściwości zmiennych tylko do odczytu, takich jak array.count. W razie wątpliwości należy dążyć do spójności z platformą.

Zasoby

Od  WWDC 2014 - 204 Co nowego w Cocoa  > 24:40 Kiedy używać @property

Użyj właściwości do wszystkiego, co dotyczy wartości lub stanu obiektu lub jego związku z innymi obiektami. Źli kandydaci:

  • Metody, które wykonują różne czynności: ładuj, analizuj, przełączaj… Mają czasowniki w nazwie.
  • Generatory: init, kopiowanie, wyliczanie,…. Te metody nie są idempotentne.
  • Metody zmieniające stan: nextObject.

Od  Swift Style autorstwa Erica Sadun  > Właściwości obliczeniowe a metody

Właściwość wyraża naturalną jakość instancji, podczas gdy metoda wykonuje akcję.

  • Metody mają parametry; właściwości nie. Preferuj metody dla każdego połączenia z efektami ubocznymi. Jeśli metoda coś robi (na przykład ładuje, analizuje, przełącza lub drukuje) lub ma nazwę czasownika, nie powinna być właściwością.
  • Preferuj właściwości prostych wartości, które możesz uzyskać i / lub ustawić.
  • Właściwości powinny wyrażać semantyczną wewnętrzną jakość instancji typu.
  • Właściwości pozwalają dodawać obserwatorów za pośrednictwem willSet i didSet. W przeciwieństwie do właściwości instancji przechowywanej, właściwości typu przechowywanego muszą zawsze mieć wartość domyślną.

konwencji kodowania Kotlin> funkcje a właściwości . Zobacz odpowiedź Daniela powyżej .

Inne zasoby bez istotnych informacji:

Jano
źródło
3

Użyłbym func. Programowanie obiektowe działa dobrze bez obliczonych właściwości. Ponieważ odzyskujesz wartość, która została obliczona / przefiltrowana, niektórzy mogą argumentować, że obliczona właściwość wydaje się właściwa. Ale oto moja skarga, jeśli to zrobisz, wtedy czytelność będzie hitem, ponieważ wydaje się to wartością.

W tym kontekście nie ma sensu przypisywanie obliczonej wartości (i na szczęście IDE pomaga nam tego uniknąć), ale co, jeśli spróbuję przypisać obliczoną wartość, która wygląda jak wartość?

event.countOfAttendees = 0; // not possible

Podczas korzystania z func dzwoniący wie, że nie masz do czynienia z wartością bezpośrednio:

event.countOfAttendees()

Myślę, że jeśli jest to obiekt behawioralny, powinien wyglądać raczej tak, jak zachowuje się niż struktura danych. Jeśli twój obiekt jest głupi i nie ma żadnego zachowania, to po co próbować go otaczać? W takim przypadku równie dobrze możesz mieć publiczność

morbidhawk
źródło