Mengapa tidak disarankan memiliki properti hanya set?

9

Hari ini di tempat kerja, salah seorang kolega saya meninjau kode saya, dan menyarankan agar saya menghapus properti hanya set dan menggunakan metode sebagai gantinya.

Ketika kami berdua sibuk dengan hal-hal lain, dia menyuruh saya untuk melihat Property Designbagian dari buku "Kerangka Desain Pedoman". Dalam buku itu penulis hanya berkata untuk menghindari:

Properti dengan setter memiliki aksesibilitas yang lebih luas daripada pengambil

Dan sekarang saya bertanya-tanya mengapa tidak disarankan untuk memiliki properti set-only? Bisakah seseorang mengklarifikasi untuk saya?

Prashant Cholachagudda
sumber
6
Bisakah Anda menggambarkan situasi di mana Anda pikir properti hanya set yang sesuai? Mungkin membuat jawaban sedikit lebih relevan.
JohnFx
1
Saya mencoba memikirkan contoh yang masuk akal secara semantik. Satu-satunya hal yang terlintas dalam pikiran adalah Passwordproperti di Userkelas. Anda dapat mengaturnya, tetapi Anda tidak bisa mendapatkannya. Anda kemudian dapat memiliki HashedPasswordproperti hanya baca . Memanggil set akan melakukan hash dan mengubah HashedPasswordproperti. Saya tidak akan meneriaki Anda jika Anda melakukan itu.
Scott Whitlock

Jawaban:

15

Saya pikir itu mungkin ada hubungannya dengan harapan. Properti set-only tidak umum dan properti biasanya digunakan untuk set "dumb" hanya untuk menyimpan nilai tanpa banyak pemrosesan. Jika Anda melakukan banyak pekerjaan dalam setter, lebih baik menggunakan metode - orang berharap metode berpotensi memakan waktu lama untuk dieksekusi dan berpotensi memiliki efek samping. Menerapkan perilaku serupa di properti dapat menghasilkan kode yang melanggar harapan.

Berikut adalah bagian yang relevan dari Pedoman Penggunaan Properti Microsoft :

Properti vs. Metode

Perancang perpustakaan kelas sering harus memutuskan antara menerapkan anggota kelas sebagai properti atau metode. Secara umum, metode mewakili tindakan dan properti mewakili data. Gunakan pedoman berikut untuk membantu Anda memilih di antara opsi-opsi ini.

  • Gunakan properti ketika anggota adalah anggota data logis. Dalam deklarasi anggota berikut, Nameadalah properti karena itu adalah anggota logis dari kelas.
public string Name
{
    get 
    {
        return name;
    }
    set 
    {
        name = value;
    }
}

Gunakan metode saat:

  • Operasi adalah konversi, seperti Object.ToString.
  • Operasi ini cukup mahal sehingga Anda ingin berkomunikasi dengan pengguna sehingga mereka harus mempertimbangkan hasil caching.
  • Memperoleh nilai properti menggunakan getpengakses akan memiliki efek samping yang dapat diamati.
  • Memanggil anggota dua kali berturut-turut menghasilkan hasil yang berbeda.
  • Urutan eksekusi itu penting. Perhatikan bahwa properti tipe harus dapat diatur dan diambil dalam urutan apa pun.
  • Anggota itu statis tetapi mengembalikan nilai yang bisa diubah.
  • Anggota mengembalikan array. Properti yang mengembalikan array bisa sangat menyesatkan. Biasanya perlu untuk mengembalikan salinan array internal sehingga pengguna tidak dapat mengubah keadaan internal. Ini, ditambah dengan fakta bahwa pengguna dapat dengan mudah menganggap itu adalah properti yang diindeks, menyebabkan kode tidak efisien. Dalam contoh kode berikut, setiap panggilan ke properti Metode membuat salinan array. Hasilnya, 2 ^ n + 1 salinan array akan dibuat di loop berikut.
Type type = // Get a type.
for (int i = 0; i < type.Methods.Length; i++)
{
   if (type.Methods[i].Name.Equals ("text"))
   {
      // Perform some operation.
   }
}

[... contoh yang dilewati lebih lama ...]

Properti Read-Only dan Write-Only

Anda harus menggunakan properti read-only ketika pengguna tidak dapat mengubah anggota data logis properti. Jangan gunakan properti tulis saja.

Adam Lear
sumber
Ya - prinsip kejutan paling tidak beroperasi di sini.
Paul Butcher
6

Karena itu tidak masuk akal dalam banyak kasus. Properti apa yang mungkin Anda miliki yang dapat Anda atur tetapi tidak dibaca?

Jika OO dimaksudkan untuk mewakili dunia nyata dengan lebih baik, properti hanya set cenderung menyarankan bahwa pemodelan Anda cukup bagus.

Sunting : Lihat juga: /programming/4564928/are-set-only-properties-bad-practice yang pada dasarnya mengatakan itu tidak intuitif dan properti hanya set pada dasarnya adalah metode dengan nama lain sehingga Anda harus menggunakan metode.

Jon Hopkins
sumber
1
Saya telah menggunakan properti set-only sebelumnya. Mereka menulis ke bidang pribadi objek untuk mengkonfigurasi perilaku itu. Mereka berguna ketika kode eksternal tidak perlu tahu nilai saat ini, tetapi mungkin perlu mengubahnya. Itu jarang, tentu saja, tetapi saya sudah melihatnya terjadi.
Mason Wheeler
@ Alasan - Saya pasti tidak akan pernah mengatakan bahwa Anda tidak boleh menggunakannya tetapi pada dasarnya mereka harus menjadi pengecualian daripada aturan.
Jon Hopkins
@MasonWheeler bukankah itu kira-kira Foo Foo { private get; set; }? Saya tidak akan menyebut itu hanya menulis
Caleth
6

Yah, saya membayangkan bahwa jika Anda dapat menetapkan properti pada sesuatu tetapi tidak pernah mendapatkannya, Anda tidak akan pernah tahu jika sesuatu yang lain mengubah / menimpa nilai yang Anda tetapkan. Itu bisa menjadi masalah jika Anda mengandalkan nilai yang Anda tetapkan, dan Anda tidak dapat (karena alasan tertentu) untuk bertahan sampai waktu yang Anda inginkan.

Menggunakan metode alih-alih properti set-only akan sedikit membingungkan bagi pengguna. The nama metode biasanya menunjukkan set- atau get , tapi nama properti biasanya tidak menunjukkan sesuatu yang dapat hanya diatur dan tidak didapat. Saya kira jika properti itu sesuatu seperti "ReadOnlyBackgroundColour" itu tidak akan membingungkan untuk coders lain, tetapi itu hanya akan terlihat aneh.

FrustratedWithFormsDesigner
sumber
Saya setuju, tetapi bagaimana metode penyetel akan berbeda dalam kasus ini?
Travis Christian
1
@ Travis Christian: Sepertinya OP bekerja dengan situasi di mana ada setter tetapi tidak ada pengambil. Jadi mereka dapat mengatur sesuatu, tetapi mereka tidak akan pernah tahu apakah itu berubah nanti.
FrustratedWithFormsDesigner
@ Frustasi Tapi mereka juga tidak akan pernah tahu apakah ada yang berubah lagi dengan metode.
Adam Lear
@Anna Lear ♦: Jika ada pengambil, Anda setidaknya dapat menguji nilainya sebelum menggunakannya jika Anda memiliki poin dalam kode Anda di mana nilai yang telah Anda tetapkan mungkin tiba-tiba ragu.
FrustratedWithFormsDesigner
3
@ Frustrasi saya setuju. Hanya saja pertanyaannya adalah tentang menggunakan properti set-only vs menggunakan metode untuk melakukan hal yang sama.
Adam Lear
-1

Ini adalah topik yang sangat lama tetapi telah melompat ke pandangan saya pada tahap akhir ini dan saya ingin beberapa komentar ketika saya mencoba membuat kasus untuk properti hanya-tulis ...

Saya memiliki satu set ActiveReportkelas yang merupakan bagian dari situs web yang dipakai dan berjalan pada postback setelah sejumlah pilihan pengguna.

Kode VB terlihat seperti ini:

  Public Class SomeReport
    Private greader As New GenericReporting.CommonReader("AStoredProcedure", 
                                      {New SqlParameter("budget_id", 0)})

    Public WriteOnly Property BudgetID As Integer
      Set(value As Integer)
        greader.Parameters("budget_id").Value = value
      End Set
    End Property

    Public Sub New(Optional budget_id As Integer = 0)
      ' This call is required by the designer.
      InitializeComponent()

      ' Add any initialization after the InitializeComponent() call.
      BudgetID = budget_id
    End Sub
  End Class

Laporan-laporan ini menggunakan nyali generik, CommonReadermengambil prosedur tersimpan dan larik default SqlParameter, yang masing-masing memiliki properti WriteOnly terkait yang, tergantung pada desain laporan, dapat diteruskan sebagai parameter pada instantiasi atau ditetapkan oleh pengguna setelah instantiasi sebelumnya memanggil Runmetode laporan .

  '''''''''''''''''''''''
  ' Parameter taken from a user selected row of a GridView
  '
  Dim SomeBudgetID As Integer = gvBudgets.SelectedDataKey.Values(budget_id)

  '''''''''''''''''''''''      
  ' On Instantiation
  '
  Dim R as ActiveReport = New SomeReport(SomeBudgetID)
  R.Run()

  '''''''''''''''''''''''      
  ' Or On Instantiation using "With" syntax
  '
  Dim R as ActiveReport = New SomeReport() With {.BudgetID = SomeBudgetID}
  R.Run()

  '''''''''''''''''''''''
  ' Or After
  '
  Dim R as ActiveReport = New SomeReport()
  R.BudgetID = SomeBudgetID
  R.Run()

Jadi, seperti yang saya lihat, memiliki properti hanya menulis dalam kasus ini

  1. Mengizinkan pemeriksaan tipe yang lebih kuat karena SqlParameterjenisnya generik
  2. Lebih fleksibel dalam membuat laporan, laporan dapat segera dipakai jika semua parameter tersedia atau ditambahkan setelah mereka menjadi tersedia.
  3. Properti mendukung sintaks "With" pada instantiation
  4. Apakah "pengambil" benar-benar diperlukan karena parameter diketahui oleh pengguna dan tidak diubah oleh Laporan?
  5. Karena SqlParameters adalah kelas dan bukan nilai primitif, Properti WriteOnly memungkinkan antarmuka yang lebih sederhana untuk pengaturan parameter

Jadi itulah pikiranku.

Bisakah saya mengubahnya menjadi metode saja? Tentu tetapi antarmuka tampaknya ... kurang bagus

  R2.BudgetID = SomeBudgetID

melawan

  R2.SetBudgetID(SomeBudgetID)
fnostro
sumber