Getters dan setters sering dikritik sebagai OO tidak tepat. Di sisi lain, sebagian besar kode OO yang saya lihat memiliki getter dan setter yang luas.
Kapan getter dan setter dibenarkan? Apakah Anda mencoba menghindari menggunakannya? Apakah mereka terlalu sering digunakan?
Jika bahasa favorit Anda memiliki properti (milik saya) maka hal-hal seperti itu juga dianggap getter dan setter untuk pertanyaan ini. Mereka adalah hal yang sama dari perspektif metodologi OO. Mereka hanya memiliki sintaks yang lebih bagus.
Sumber untuk Pengritik Getter / Setter (beberapa diambil dari komentar untuk memberikan visibilitas yang lebih baik):
- http://www.javaworld.com/javaworld/jw-09-2003/jw-0905-toolbox.html
- http://typicalprogrammer.com/?p=23
- http://c2.com/cgi/wiki?AccessorsAreEvil
- http://www.darronschall.com/weblog/2005/03/no-brain-getter-and-setters.cfm
- http://www.adam-bien.com/roller/abien/entry/encapsulation_violation_with_getters_and
- http://www.yegor256.com/2014/09/16/getters-and-setters-are-evil.html
Untuk menyatakan kritik secara sederhana: Getters and Setters memungkinkan Anda untuk memanipulasi keadaan internal objek dari luar objek. Ini melanggar enkapsulasi. Hanya objek itu sendiri yang harus peduli dengan keadaan internalnya.
Dan contoh kode versi prosedural.
struct Fridge
{
int cheese;
}
void go_shopping(Fridge fridge)
{
fridge.cheese += 5;
}
Versi kode mutator:
class Fridge
{
int cheese;
void set_cheese(int _cheese) { cheese = _cheese; }
int get_cheese() { return cheese; }
}
void go_shopping(Fridge fridge)
{
fridge.set_cheese(fridge.get_cheese() + 5);
}
Para pengambil dan pembuat membuat kode jauh lebih rumit tanpa memberikan enkapsulasi yang tepat. Karena keadaan internal dapat diakses oleh objek lain kami tidak mendapatkan banyak dengan menambahkan getter dan setter ini.
Pertanyaan sebelumnya telah dibahas pada Stack Overflow:
sumber
Getters and setters are often criticized as being not proper OO
- Tolong kutip.Jawaban:
Memiliki getter dan setter tidak dengan sendirinya merusak enkapsulasi. Apa yang memecahkan enkapsulasi secara otomatis menambahkan pengambil dan penyetel untuk setiap anggota data (setiap bidang , dalam istilah java), tanpa memikirkannya. Meskipun ini lebih baik daripada membuat semua anggota data publik, itu hanya satu langkah kecil.
Maksud enkapsulasi bukanlah bahwa Anda seharusnya tidak dapat mengetahui atau mengubah keadaan objek dari luar objek, tetapi bahwa Anda harus memiliki kebijakan yang masuk akal untuk melakukannya.
Beberapa anggota data mungkin sepenuhnya internal ke objek, dan seharusnya tidak memiliki getter atau setter.
Beberapa anggota data harus hanya-baca, sehingga mereka mungkin membutuhkan getter tetapi tidak setter.
Beberapa anggota data mungkin harus tetap konsisten satu sama lain. Dalam kasus seperti itu Anda tidak akan menyediakan setter untuk masing-masing, tetapi metode tunggal untuk mengaturnya pada saat yang sama, sehingga Anda dapat memeriksa nilai-nilai untuk konsistensi.
Beberapa anggota data mungkin hanya perlu diubah dengan cara tertentu, seperti bertambah atau dikurangi dengan jumlah yang tetap. Dalam hal ini, Anda akan memberikan metode
increment()
dan / ataudecrement()
, bukannya setter.Namun yang lain mungkin benar-benar perlu membaca-menulis, dan akan memiliki baik pengambil dan pembuat.
Pertimbangkan contoh a
class Person
. Katakanlah seseorang memiliki nama, nomor jaminan sosial, dan usia. Katakanlah kita tidak mengizinkan orang mengubah nama atau nomor jaminan sosial mereka. Namun, usia seseorang harus bertambah 1 setiap tahun. Dalam hal ini, Anda akan memberikan konstruktor yang akan menginisialisasi nama dan SSN ke nilai yang diberikan, dan yang akan menginisialisasi usia menjadi 0. Anda juga akan memberikan metodeincrementAge()
, yang akan menambah usia dengan 1. Anda juga akan memberikan getter untuk ketiganya. Tidak ada setter diperlukan dalam kasus ini.Dalam desain ini Anda membiarkan keadaan objek diperiksa dari luar kelas, dan Anda membiarkannya diubah dari luar kelas. Namun, Anda tidak mengizinkan negara diubah secara sewenang-wenang. Ada kebijakan, yang secara efektif menyatakan bahwa nama dan SSN tidak dapat diubah sama sekali, dan bahwa usia dapat bertambah 1 tahun sekaligus.
Sekarang katakanlah seseorang juga memiliki gaji. Dan orang-orang dapat berganti pekerjaan sesuka hati, yang berarti gajinya juga akan berubah. Untuk memodelkan situasi ini kita tidak memiliki cara lain selain memberikan
setSalary()
metode! Mengizinkan gaji diubah sesuka hati adalah kebijakan yang masuk akal untuk kasus ini.By the way, dalam contoh Anda, saya akan memberikan kelas
Fridge
yangputCheese()
dantakeCheese()
metode, bukanget_cheese()
danset_cheese()
. Maka Anda masih akan memiliki enkapsulasi.sumber
Alasan dasar untuk getter dan setter di Jawa sangat sederhana:
Oleh karena itu, jika Anda ingin mengizinkan bidang untuk melewati antarmuka, Anda akan memerlukan metode pembaca dan penulis. Ini secara tradisional disebut getX dan setX untuk bidang x.
sumber
Dari http://www.adam-bien.com/roller/abien/entry/encapsulation_violation_with_getters_and
Gaya JavaBean:
OO-style:
Yah, jelas saya lebih suka pendekatan yang terakhir; itu tidak berdarah detail implementasi, itu lebih sederhana dan lebih ringkas, dan semua informasi yang diperlukan disertakan dengan pemanggilan metode, sehingga lebih mudah untuk memperbaikinya. Saya juga lebih suka mengatur anggota pribadi menggunakan parameter di konstruktor, bila memungkinkan.
Pertanyaan Anda adalah, kapan seorang pengambil dan pembuat dibenarkan? Mungkin ketika perubahan mode diperlukan, atau Anda perlu menginterogasi objek untuk beberapa informasi.
Dalam memikirkannya, ketika saya pertama kali mulai membuat kode dalam C #, saya menulis banyak kode dengan gaya bahasa Jawa yang digambarkan di atas. Tetapi ketika saya memperoleh pengalaman dalam bahasa, saya mulai melakukan lebih banyak pengaturan anggota dalam konstruktor, dan menggunakan metode yang lebih mirip gaya OO di atas.
sumber
Ketika perilaku "get" dan "set" benar-benar cocok dengan perilaku dalam model Anda, yang praktis tidak pernah .
Setiap penggunaan lainnya hanyalah cheat karena perilaku domain bisnis tidak jelas.
Sunting
Jawaban itu mungkin terdengar kurang ajar, jadi izinkan saya memperluas. Jawaban di atas sebagian besar benar tetapi fokus pada paradigma pemrograman desain OO dan beberapa yang melewatkan gambaran besar. Dalam pengalaman saya ini membuat orang berpikir bahwa menghindari gettings dan setters adalah beberapa aturan akademik untuk bahasa pemrograman OO (misalnya orang berpikir mengganti getter dengan properti adalah hal yang bagus)
Sebenarnya itu adalah konsekuensi dari proses desain. Anda tidak harus masuk ke antarmuka dan enkapsulasi dan pola, berdebat apakah itu merusak atau tidak paradigma ini dan apa atau tidak pemrograman OO yang baik. Satu-satunya hal yang pada akhirnya penting adalah bahwa jika tidak ada apa pun di domain Anda yang berfungsi seperti ini dengan meletakkannya di Anda, bukan memodelkan domain Anda.
Kenyataannya adalah bahwa sangat tidak mungkin bahwa sistem di ruang domain Anda memiliki getter dan setter. Anda tidak dapat menghampiri pria atau wanita yang bertanggung jawab atas penggajian dan hanya mengatakan "Setel gaji ini ke X" atau "Ambilkan saya gaji ini" . Perilaku seperti itu tidak ada
Jika Anda memasukkan ini ke dalam kode Anda, Anda tidak mendesain sistem Anda agar sesuai dengan model domain Anda. Ya itu merusak antarmuka dan enkapsulasi, tetapi bukan itu intinya. Intinya adalah Anda memodelkan sesuatu yang tidak ada.
Terlebih lagi Anda mungkin kehilangan langkah atau proses penting, karena mungkin ada alasan saya tidak bisa hanya berjalan untuk membayar dan mengatakan menetapkan gaji ini ke X.
Ketika orang menggunakan getter dan setter, mereka cenderung mendorong aturan untuk proses ini ke tempat yang salah. Ini semakin menjauh dari domain Anda. Menggunakan contoh dunia nyata, itu seperti gaji dengan asumsi bahwa orang yang berjalan secara acak memiliki izin untuk mendapatkan nilai-nilai ini jika tidak dia tidak akan meminta mereka. Bukan hanya bukan karena domain itu, sebenarnya berbohong tentang bagaimana domain itu.
sumber
set/get
gaji?Sebagai aturan umum, getter dan setter adalah ide yang buruk. Jika bidang tidak secara logis bagian dari antarmuka dan Anda menjadikannya pribadi, tidak apa-apa. Jika secara logis bagian dari antarmuka dan Anda membuatnya publik, itu bagus. Tetapi jika Anda menjadikannya pribadi dan kemudian berbalik dan menjadikannya publik secara efektif lagi dengan menyediakan pengambil dan penyetel, Anda kembali ke tempat Anda memulai kecuali kode Anda sekarang lebih bertele-tele dan dikaburkan.
Jelas, ada pengecualian. Di Jawa, Anda mungkin perlu menggunakan antarmuka. Pustaka standar Java memiliki persyaratan kompatibilitas yang sangat ekstrem sehingga melebihi ukuran kualitas kode yang normal. Bahkan mungkin Anda benar-benar berurusan dengan kasus yang legendaris namun langka di mana ada peluang bagus Anda nantinya dapat mengganti bidang yang tersimpan dengan perhitungan sambil jalan tanpa melanggar antarmuka. Tapi ini pengecualian. Getters dan setter adalah anti-pola yang membutuhkan pembenaran khusus.
sumber
apakah bidang dapat diakses secara langsung atau melalui metode tidak benar-benar penting.
Invarian kelas (yang berguna) penting. Dan untuk melestarikannya, kita kadang-kadang tidak perlu bisa mengubah sesuatu dari luar. Misalnya. jika kita memiliki class Square dengan lebar dan tinggi yang terpisah, mengubah salah satunya menjadi sesuatu yang lain daripada persegi. Jadi kita perlu metode changeSide. Jika itu adalah Rectangle, kita bisa memiliki setter / bidang publik. Tapi setter daripada akan menguji apakah lebih besar dari nol akan lebih baik.
Dan dalam bahasa konkret (mis. Java) adalah alasan mengapa kita membutuhkan metode tersebut (antarmuka). Dan alasan lain untuk metode ini adalah kompatibilitas (sumber dan biner). Jadi lebih mudah untuk menambahkannya kemudian pikirkan apakah bidang publik sudah cukup.
btw. Saya suka menggunakan kelas holding nilai abadi yang tidak berubah dengan bidang final publik.
sumber
Anda mungkin ingin mengubah internal Anda ke apa pun sambil menjaga antarmuka yang sama. Jika antarmuka Anda tidak bervariasi, mereka yang Anda kode tidak akan rusak. Anda masih dapat mengubah internal Anda seperti yang Anda inginkan.
sumber
Pendekatan saya adalah ini -
Ketika saya berharap untuk menipu dengan data nanti, pengambil / penyetel dibenarkan. Juga, jika perubahan terjadi, saya sering mendorong data menjadi pengambil / penyetel.
Jika struktur POD, saya membiarkan slot tersedia.
Pada tingkat yang lebih abstrak, pertanyaannya adalah "siapa yang mengelola data", dan itu tergantung pada proyek.
sumber
Jika menggunakan getter dan setter terasa rumit, masalahnya mungkin bahasa, bukan konsep itu sendiri.
Berikut kode dari contoh kedua yang ditulis dalam Ruby:
Perhatikan itu terlihat sangat mirip dengan contoh pertama di Jawa? Ketika getter dan setter diperlakukan sebagai warga negara kelas satu, mereka bukan tugas untuk digunakan, dan fleksibilitas tambahan kadang-kadang bisa menjadi keuntungan nyata - misalnya, kita bisa memutuskan untuk mengembalikan nilai default untuk keju di lemari es baru:
Tentu saja akan ada banyak variabel yang seharusnya tidak diekspos secara publik sama sekali. Mengekspos variabel internal yang tidak perlu akan membuat kode Anda lebih buruk, tetapi Anda tidak bisa menyalahkan itu pada getter dan setter.
sumber
Pertimbangkan
Size
kelas yang merangkum lebar dan tinggi. Saya bisa menghilangkan setter dengan menggunakan konstruktor tetapi bagaimana itu membantu saya menggambar persegi panjang denganSize
? Lebar dan tinggi bukan data internal ke kelas; mereka berbagi data yang harus tersedia untuk konsumen Ukuran.Objek terdiri dari perilaku dan keadaan - atau atribut. Jika tidak ada keadaan terbuka maka hanya perilaku yang bersifat publik.
Tanpa status, bagaimana Anda menyortir koleksi benda? Bagaimana Anda mencari contoh objek tertentu? Jika Anda hanya menggunakan konstruktor, apa yang terjadi ketika objek Anda memiliki daftar atribut yang panjang?
Tidak ada parameter metode yang boleh dikonsumsi tanpa validasi. Karena itu malas menulis:
Jika Anda menulisnya dengan cara itu maka Anda setidaknya sudah siap untuk menggunakan setter untuk validasi; itu lebih baik daripada bidang publik - tetapi nyaris. Tetapi setidaknya Anda memiliki antarmuka publik yang konsisten sehingga Anda dapat kembali dan memasukkan aturan validasi tanpa melanggar kode pelanggan Anda.
Getters, setter, properti, mutator, sebut mereka apa yang Anda mau, tetapi mereka perlu.
sumber
int
variabel instan, misalnya, dan bayangkan Anda memutuskan untuk menambahkan aturan validasi untuk hanya menerima nilai-nilai yang tidak negatif. Masalahnya adalah bahwa kode pelanggan Anda mungkin sudah bergantung pada kemungkinan untuk menetapkannya ke nilai negatif ...Jika getter dan seter melanggar enkapsulasi dan OO sejati, maka saya serius dalam masalah.
Saya selalu merasa objek mewakili apa pun yang terlintas dalam pikiran bahwa Anda perlu melakukannya.
Saya baru saja selesai menulis sebuah program yang menghasilkan Maze di Jawa, dan saya memiliki kelas yang mewakili "Kotak Maze". Saya memiliki data di kelas ini yang mewakili koordinat, dinding, dan boolean, dll.
Saya harus memiliki beberapa cara untuk mengubah / memanipulasi / mengakses data ini! Apa yang saya lakukan tanpa getter dan setter? Java tidak menggunakan properti dan mengatur semua data saya yang bersifat lokal untuk kelas ini ke publik adalah PASTI pelanggaran enkapsulasi dan OO.
sumber
Pertama ada dua jenis objek yang akan saya komentari, nilai dan jenis layanan.
Jenis layanan tidak boleh memiliki setter, dependensi apa pun yang mereka butuhkan tidak dapat diperoleh. Cara terbaik untuk melewati dependensi adalah melalui konstruktor atau pabrik dengan cara itu semua instance sepenuhnya terbentuk dari awal, sederhana dan sederhana.
Jenis nilai juga harus tidak berubah, di sisi lain ada saat-saat ini tidak praktis seperti ORM, atau beberapa pemetaan lain seperti dari widget ke objek. Semua tipe nilai lain yang dapat melewati sistem dari satu lapisan atau bagian ke lapisan lain harus tidak berubah dan tidak boleh memiliki setter.
sumber
Getter / Setter dibenarkan sama seperti metode publik lainnya dibenarkan. Pembenaran ini terutama karena kami ingin menyediakan antarmuka ke dunia luar yang mendefinisikan bagaimana kelas kami berinteraksi dengan kelas-kelas lain. Kami melakukan ini terutama karena kami ingin mengurangi sambungan antara entitas yang terpisah. Mengurangi sambungan adalah hal yang baik karena berbagai alasan:
sumber
Ya, getter dan setter adalah anti-pola dalam pemrograman berorientasi objek dan tidak boleh digunakan: http://www.yegor256.com/2014/09/16/getters-and-setters-are-evil.html . Singkatnya, mereka tidak cocok dengan paradigma berorientasi objek karena mereka mendorong Anda untuk memperlakukan objek seperti struktur data. Yang merupakan kesalahpahaman besar.
sumber
Saya berharap bahwa apa pun yang dikembangkan oleh perusahaan IDE yang mengembangkan bahasa pemrograman Anda secara otomatis tidak melanggar "Prinsip Orientasi Objek".
Yang sedang berkata, setiap kali Anda memiliki variabel cakupan publik, gunakan pengambil dan penyetel dan Anda emas. Menurut saya elemen yang diperlukan dari prinsip enkapsulasi yang sangat berorientasi objek - bahkan jika itu terlihat seperti banyak kode barang rongsokan.
Alasan untuk menggunakannya adalah bahwa enkapsulasi yang tepat mungkin belum terjadi dan selama Anda telah mengabstraksi lapisan yang memungkinkan orang yang sedang bermain dengan objek Anda merasakan objek Anda, Anda dapat mengambil objek itu tanpa dia menyadarinya kan?
Cukuplah untuk mengatakan, sebuah rumah yang terbagi tidak dapat berdiri, salah satu penyewa OO tidak akan menyalakan dirinya sendiri dan Anda tidak dapat melayani enkapsulasi dan optimasi prematur.
sumber
Saya pikir kita akan memiliki jawaban yang lebih biasa di sini?
Getters dan setters pada umumnya sangat OOP (ada yang mengatakan hal lain salah, sesederhana itu).
Meskipun Anda harus ingat untuk tidak over engineer, jangan pernah membuat rajin atau rajin yang tidak diperlukan. Informasi apa pun yang tidak akan Anda gunakan oleh kelas lain Anda tidak boleh memiliki pengambil atau penyetel untuk.
Padahal, alasan mengapa Anda tidak membuat bidang publik dan sebaliknya memiliki getter dan setter kebanyakan:
Tes yang tepat tidak mungkin dilakukan dengan menggunakan bidang. Getters / setter jauh lebih baik dalam hal itu.
Tidak mungkin menggunakan bidang dengan benar dalam pengaturan pemrograman waktu nyata. Getter / setter yang disinkronkan adalah cara untuk pergi.
Topik antarmuka (sudah dijelaskan jadi saya tidak akan).
Lebih mudah digunakan ketika menggunakan kembali sistem dengan benar.
Jauh lebih sulit untuk mengetahui kelas mana yang menggunakan kelas Anda dan apa yang akan pecah jika Anda mengubah bidang daripada pengambil / penyetel.
Untuk itu satu-satunya saat Anda menggunakan bidang publik alih-alih pengambil / penyetel adalah ketika Anda tidak membuat proyek resmi, melainkan hanya melakukannya untuk bersenang-senang dan tidak dapat repot-repot dengan pengambil / penyetel.
sumber