Fungsi cepat vs properti yang dihitung

26

Katakanlah saya memiliki kelas Eventsebagai berikut:

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

Apakah praktik terbaik untuk menggunakan fungsi atau properti yang dihitung dalam 2 kasus yang ditunjukkan di atas?

Ashley Mills
sumber
2
stackoverflow.com/questions/24035276/… ... Singkatnya: 'Biarkan fungsi Anda menjadi fungsi, dan properti Anda menjadi properti.'
Robert Harvey

Jawaban:

14

Ikuti Prinsip Akses Seragam ,

Semua layanan yang ditawarkan oleh modul harus tersedia melalui notasi yang seragam, yang tidak mengkhianati apakah itu diimplementasikan melalui penyimpanan atau melalui perhitungan

Bagi saya, ini berarti bahwa saya tidak menulis funcs yang tidak mengambil argumen dan mengembalikan nilai. Saya selalu menggunakan properti yang dihitung. Dengan begitu, jika saya kemudian memutuskan untuk mengubah properti yang dikomputasi menjadi properti yang disimpan, saya dapat melakukannya tanpa memiliki keinginan untuk menghapus parens di mana-mana di aplikasi saya dan tanpa memiliki metode "pengambil" yang terpisah yang hanya mengembalikan nilai yang tersimpan properti, yang tampaknya IMHO boros.

Dan jika saya mengubah properti tersimpan menjadi properti yang dihitung, saya tidak perlu menambahkan parens di akhir, dan di mana pun ia digunakan dalam aplikasi.

Daniel T.
sumber
Saya awalnya pergi dengan jawaban kompleksitas @ Anton, tetapi dalam praktek saya menyadari bahwa ini adalah cara saya melakukannya ... properti secara default.
Ashley Mills
17

Saya akan mengatakan itu tergantung pada kompleksitas perhitungan vs frekuensi penggunaan.

  • Jika O(1)/ *, maka gunakan properti yang dihitung.
  • Jika O(N)+/ rare-use, maka gunakan fungsi.
  • Jika itu O(N)+/ frequent-use, pikirkan apakah di masa depan Anda mungkin memutuskan untuk menggunakan caching atau teknik "pintar" lainnya untuk mengkompensasi kompleksitas, jika "ya" lalu gunakan properti, jika "tidak-tidak-tidak, itu hanya berat" lalu gunakan fungsi .
sopan santun
sumber
2
Lucu bagaimana saya mulai melakukannya dengan menggunakan alasan yang sama. Jika Anda "bisa" memberikan kesan sebagai properti, bahkan jika Anda harus membuat pemrosesan yang ringan, selama itu tidak mengubah objek, jadikan itu properti.
Penjualan Dielson
9

Saya baru-baru ini mulai belajar Kotlin dan mereka memiliki heuristik yang hebat tentang kapan harus menggunakan properti yang dihitung:

Fungsi vs Properti

Dalam beberapa kasus, fungsi tanpa argumen mungkin dapat dipertukarkan dengan properti hanya baca. Meskipun semantiknya serupa, ada beberapa konvensi gaya tentang kapan lebih suka satu sama lain.

Lebih suka properti daripada fungsi ketika algoritma yang mendasarinya:

  • tidak melempar
  • memiliki kompleksitas O (1)
  • murah untuk dihitung (atau dihitung pada putaran pertama)
  • mengembalikan hasil yang sama atas permintaan

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

Daniel T.
sumber
'Tidak melempar' juga penting bagi Swift karena properti tidak dapat melempar (belum?)
alejandromp
"memiliki kompleksitas O (1)" telah dihapus dari dokumentasi
Mahmoud Shahoud
7

Di Swift, fungsi tanpa parameter dan properti yang dihitung memiliki kemampuan yang hampir sama (mungkin ada perbedaan bahwa fungsi tanpa parameter juga merupakan penutupan, sedangkan properti yang dihitung tidak).

Perbedaannya secara semantik. Jika kode Anda melakukan suatu tindakan dan mengembalikan misalnya deskripsi hasil dari tindakan itu, maka saya akan menggunakan suatu fungsi. Jika kode Anda menghitung properti tetapi dari sudut pandang pengguna, ini bisa berupa properti tersimpan, atau mungkin properti tersimpan yang mengharuskan memperbarui beberapa nilai yang di-cache terlebih dahulu, maka saya akan menggunakan properti yang dihitung.

Perbedaan besar: Apa yang terjadi jika Anda memanggil fungsi atau properti yang dihitung dua kali? Untuk properti yang dihitung saya berharap bahwa x = properti; y = properti memiliki perilaku yang sama persis dengan x = properti; y = x kecuali itu mungkin berjalan sedikit lebih lambat. Untuk fungsi, saya tidak akan terkejut jika perilakunya berbeda.

gnasher729
sumber
4

Gunakan countOfAttendeesdan countOfPaidAttendees().


Variabel yang dihitung adalah variabel yang mengembalikan nilai yang dihitung setiap kali diakses. Artinya, itu tidak menyimpan nilai. Secara internal itu diimplementasikan sebagai fungsi.

Apa bedanya dengan fungsi?

  • Secara semantik, variabel adalah status, fungsi adalah tindakan.
  • Suatu fungsi mengatur akses ke penyimpanan pribadi. Variabel yang dihitung dapat melakukan hal yang sama dengan cara yang lebih kompak. Contoh .
  • Variabel terkomputasi dapat digunakan dengan KVO, diteruskan sebagai #keypath, dan memiliki fasilitas untuk mengamati: willSet, didSet.

Anda harus menggunakan variabel kapan

  • itu tidak melempar
  • mengembalikan properti sederhana
  • itu tidak memiliki efek samping atau kata kerja dalam namanya
  • itu O (1), artinya, itu tidak menimbulkan biaya yang signifikan. Dalam contoh Anda itu akan menjadi O (n).
  • itu idempoten. Beberapa doa identik mengembalikan nilai yang sama atau mengatur objek ke keadaan yang sama.

Alasan yang tidak relevan untuk memilih variabel daripada fungsi

  • Variabel yang dihitung menyelamatkan Anda dari mengetik (). Namun, kejelasan lebih penting daripada keringkasan, jadi ini adalah argumen yang lemah.
  • Variabel read only dapat ditimpa sebagai baca / tulis. Suatu fungsi menunjukkan bahwa itu selalu hanya baca. Namun, Apple menggunakan properti untuk variabel read-only seperti array.count. Ketika ragu mencari konsistensi dengan platform.

Sumber daya

Dari  WWDC 2014 - 204 Apa yang baru di Cocoa  > 24:40 Kapan menggunakan @property

Gunakan properti untuk apa pun yang tentang nilai atau keadaan suatu objek atau hubungannya dengan objek lain. Kandidat buruk:

  • Metode yang melakukan hal-hal: memuat, mengurai, beralih, .... Mereka memiliki kata kerja dalam namanya.
  • Generator: init, salin, disebutkan, .... Metode-metode ini tidak idempoten.
  • Metode yang mengubah status: nextObject.

Dari  Swift Style oleh Erica Sadun  > Computed Properties vs. Methods

Properti mengungkapkan kualitas yang melekat pada instance, sementara metode melakukan tindakan.

  • Metode memiliki parameter; properti tidak. Memilih metode untuk panggilan apa pun dengan efek samping. Jika suatu metode melakukan sesuatu (misalnya, ia memuat, mem-parsing, mengubah, atau mencetak) atau memiliki nama kata kerja, itu tidak boleh menjadi properti.
  • Memilih properti untuk nilai-nilai sederhana yang bisa Anda dapatkan dan / atau atur.
  • Properti harus mengekspresikan kualitas intrinsik semantik dari instance type.
  • Properti memungkinkan Anda untuk menambahkan pengamat melalui willSet dan didSet. Tidak seperti properti instance tersimpan, properti tipe tersimpan harus selalu diberi nilai default.

Dari  konvensi pengkodean Kotlin> fungsi vs properti . Lihat jawaban Daniel di atas .

Sumber daya lain tanpa informasi yang relevan:

Jano
sumber
3

Saya akan menggunakan func. Pemrograman berorientasi objek bekerja dengan baik tanpa properti yang dihitung. Karena Anda mendapatkan nilai kembali yang dihitung / difilter, beberapa orang mungkin berpendapat bahwa properti yang dikomputasi terasa benar. Tapi inilah keluhan saya, jika Anda melakukannya maka keterbacaan terkena, karena rasanya seperti nilai.

Dalam konteks ini tidak masuk akal untuk mencoba menetapkan nilai yang dihitung (dan untungnya IDE membantu kita menghindari ini) tetapi bagaimana jika saya mencoba menetapkan sesuatu yang dihitung tetapi terlihat seperti nilai?

event.countOfAttendees = 0; // not possible

Saat menggunakan func pemanggil tahu Anda tidak berurusan dengan nilai secara langsung:

event.countOfAttendees()

Saya pikir jika ini merupakan objek perilaku yang seharusnya terlihat berperilaku daripada terlihat seperti struktur data. Jika objek Anda bodoh dan tidak memiliki perilaku apa pun, mengapa mencoba merangkumnya? Dalam hal ini Anda mungkin hanya memiliki peserta untuk umum

morbidhawk
sumber