Apa masalah yang tepat dengan memungkinkan getter?

15

Saya tidak melihat pendapat tentang semantik tetapi hanya untuk kasus di mana memiliki getter yang digunakan secara bijaksana adalah halangan yang sebenarnya. Mungkin itu melemparkan saya ke dalam spiral yang tidak pernah berakhir dengan mengandalkan mereka, mungkin alternatifnya lebih bersih dan menangani getter secara otomatis, dll. Sesuatu yang konkret.

Saya telah mendengar semua argumen, saya mendengar bahwa mereka buruk karena memaksa Anda memperlakukan objek sebagai sumber data, bahwa mereka melanggar "keadaan murni" objek dari "jangan berikan terlalu banyak tetapi bersiaplah untuk terima banyak ".

Tapi sama sekali tidak ada alasan masuk akal mengapa a getDataadalah hal yang buruk, pada kenyataannya, beberapa orang berpendapat bahwa itu banyak tentang semantik, getter baik-baik saja, tetapi jangan beri nama getX, bagi saya, ini setidaknya lucu .

Apa satu hal, tanpa pendapat, yang akan rusak jika saya menggunakan getter secara masuk akal dan untuk data yang jelas integritas objeknya tidak pecah jika dipadamkan?

Tentu saja itu memungkinkan pengambil untuk string yang digunakan untuk mengenkripsi sesuatu adalah di luar bodoh, tapi saya sedang berbicara tentang data yang sistem Anda perlu berfungsi. Mungkin data Anda ditarik melalui Providerdari objek, tetapi, masih, objek masih perlu untuk memungkinkan Provideruntuk melakukan $provider[$object]->getData, tidak ada jalan lain.


Mengapa saya bertanya: Bagi saya, getter, ketika digunakan dengan bijaksana dan pada data yang diperlakukan sebagai "aman" dikirim oleh Tuhan, 99% dari getter saya digunakan untuk mengidentifikasi objek, seperti dalam, saya bertanya, melalui kode Object, what is your name? Object, what is your identifier?, siapa pun yang bekerja dengan suatu objek harus mengetahui hal-hal ini tentang suatu objek, karena hampir semua hal tentang pemrograman adalah identitas dan siapa lagi yang lebih tahu apa itu daripada objek itu sendiri? Jadi saya gagal melihat masalah nyata kecuali Anda seorang purist.

Saya telah melihat semua pertanyaan StackOverflow tentang "mengapa getter / setter" buruk dan meskipun saya setuju bahwa setter benar-benar buruk dalam 99% kasus, getter tidak harus diperlakukan sama hanya karena mereka berima.

Setter akan membahayakan identitas objek Anda dan membuatnya sangat sulit untuk men-debug siapa yang mengubah data, tetapi seorang pengambil tidak melakukan apa-apa.

coolpasta
sumber
2
Saran saya adalah melupakan sebagian besar teori OO. Praktek. Tulis banyak kode, lalu pertahankan. Anda akan belajar jauh, jauh, jauh lebih banyak tentang apa yang bekerja dengan baik dan apa yang tidak dari benar-benar melakukan sesuatu dan kemudian kembali ke sana beberapa bulan kemudian.
jpmc26
1
@ jpmc26 Apa yang ada di ibunda .... Saya tidak pernah benar-benar menyadari bahwa tidak ada dari kita yang benar-benar melakukan OOP dengan benar, saya selalu memiliki gagasan enkapsulasi yang secara ketat berkaitan dengan bidang objek, tetapi objek itu sendiri adalah keadaan dan sedang dibagikan secara bebas. Benar-benar semua orang melakukan OOP yang salah, maka, atau lebih tepatnya, OOP tidak mungkin jika paradigma itu objek. Saya menggunakan OOP secara ketat untuk mengekspresikan cara kerja sistem dan tidak pernah memperlakukannya sebagai grail suci, atau SOLID. Mereka hanya alat yang saya gunakan sebagian besar untuk mendefinisikan konsep saya yang cukup baik (melalui implementasi). Adakah yang membaca jika ini benar?
coolpasta
2
--cont, Semakin banyak saya menulis, semakin saya sadari bahwa pemrograman adalah semua tentang kemampuan untuk abstrak sebanyak yang diperlukan untuk dapat bernalar, kepada orang lain, juga kepada Anda tentang basis kode Anda. Tentu saja, sisi teknisnya adalah memastikan Anda melakukan pemeriksaan yang tepat / menetapkan aturan yang benar. Sebenarnya, siapa pun yang berhasil membuat orang lain memahami kode mereka akan menang dengan lebih baik. Pastikan masuk akal bagi siapa saja yang membacanya, lalu pastikan itu tidak gagal dengan melakukan segmentasi objek dengan antarmuka, mengecek dan beralih ke paradigma lain dengan lebih mudah ketika lebih mudah untuk menjelaskannya: menjadi fleksibel.
coolpasta
2
Bagi saya ini kelihatan seperti jerami. Saya tidak percaya ada pengembang serius yang benar-benar menulis kode yang dapat digunakan akan berpendapat bahwa menggunakan getter dengan bijaksana adalah masalah. Pertanyaannya mengimplikasikan getter dapat digunakan secara masuk akal yang selanjutnya mengimplikasikan getter dapat masuk akal. Apakah Anda mencari seseorang untuk mengatakan tidak ada penggunaan getter yang masuk akal? Anda akan menunggu sebentar.
JimmyJames
2
@coolpasta Anda benar. Saya tidak terlalu peduli apakah itu murni OOP. Lebih baik. Beri saya pilihan antara kode rusak yang dapat dipahami oleh manusia vs kode mencintai CPU sempurna yang tidak dapat diuraikan dan saya akan mengambil kode ramah manusia setiap waktu. OOP HANYA berguna bagi saya ketika mengurangi jumlah hal yang harus saya pikirkan pada satu waktu. Itulah satu-satunya alasan saya suka itu karena prosedural langsung. Tanpa itu Anda hanya membuat saya melompati banyak file kode sumber tanpa alasan.
candied_orange

Jawaban:

22

Anda tidak dapat menulis kode yang baik tanpa getter.

Alasan mengapa bukan karena getter tidak merusak enkapsulasi, mereka melakukannya. Bukan karena getter tidak menggoda orang untuk tidak mengikuti OOP yang akan membuat mereka menggunakan metode dengan data yang mereka tindak lanjuti. Mereka melakukannya. Tidak, Anda perlu getter karena batasan.

Ide-ide enkapsulasi dan menjaga metode bersama-sama dengan data yang mereka lakukan tidak berfungsi ketika Anda mengalami batas yang membuat Anda tidak bisa memindahkan metode dan memaksa Anda untuk memindahkan data.

Sangat sederhana. Jika Anda menggunakan getter ketika tidak ada batas Anda akhirnya tidak memiliki objek nyata. Semuanya mulai cenderung prosedural. Yang bekerja sebaik yang pernah dilakukannya.

OOP sejati bukanlah sesuatu yang bisa Anda sebarkan ke mana-mana. Itu hanya bekerja dalam batas-batas itu.

Batas-batas itu tidak tipis. Mereka memiliki kode di dalamnya. Kode itu tidak boleh OOP. Itu juga tidak bisa berfungsi. Tidak ada kode ini yang dicabut dari cita-cita kita sehingga dapat menghadapi kenyataan pahit.

Michael Fetters menyebut kode ini fascia setelah jaringan ikat putih yang menyatukan bagian-bagian jeruk.

Ini adalah cara yang bagus untuk memikirkannya. Ini menjelaskan mengapa tidak masalah memiliki kedua jenis kode dalam basis kode yang sama. Tanpa perspektif ini banyak programmer baru yang berpegang teguh pada cita-cita mereka, maka hati mereka hancur dan menyerah pada cita-cita ini ketika mereka mencapai batas pertama mereka.

Cita-cita hanya bekerja di tempat yang seharusnya. Jangan menyerah pada mereka hanya karena mereka tidak bekerja di mana-mana. Gunakan mereka di tempat mereka bekerja. Tempat itu adalah bagian berair yang dilindungi fasia.

Contoh sederhana dari batas adalah koleksi. Ini menyimpan sesuatu dan tidak tahu apa itu. Bagaimana mungkin seorang perancang koleksi dapat memindahkan fungsionalitas perilaku objek yang dipegang ke dalam koleksi ketika mereka tidak tahu apa yang akan dipegangnya? Kamu tidak bisa Anda menghadapi batas. Itulah sebabnya koleksi memiliki getter.

Sekarang jika Anda tahu, Anda bisa memindahkan perilaku itu, dan menghindari keadaan bergerak. Ketika Anda tahu, Anda harus melakukannya. Anda tidak selalu tahu.

Beberapa orang menyebut ini pragmatis. Dan itu. Tapi senang mengetahui mengapa kita harus pragmatis.


Anda telah menyatakan bahwa Anda tidak ingin mendengar argumen semantik dan tampaknya menganjurkan menempatkan "pengambil yang masuk akal" di mana-mana. Anda meminta ide ini ditantang. Saya pikir saya bisa menunjukkan ide memiliki masalah dengan cara Anda membingkainya. Tetapi saya pikir saya tahu dari mana Anda berasal karena saya pernah ke sana.

Jika Anda ingin getter di mana-mana lihatlah Python. Tidak ada kata kunci pribadi. Namun Python melakukan OOP dengan baik. Bagaimana? Mereka menggunakan trik semantik. Mereka menyebut segala sesuatu yang dimaksudkan untuk menjadi pribadi dengan garis bawah terkemuka. Anda bahkan diizinkan membaca darinya asalkan Anda bertanggung jawab untuk melakukannya. "Kita semua orang dewasa di sini", kata mereka.

Jadi apa perbedaan antara itu dan menempatkan getter pada semua yang ada di Java atau C #? Maaf tapi ini semantik. Konvensi Piton menggarisbawahi dengan jelas memberi sinyal kepada Anda bahwa Anda mencari-cari di balik pintu satu-satunya karyawan. Tampar getter pada semuanya dan Anda kehilangan sinyal itu. Dengan refleksi Anda bisa menanggalkan privasi dan tetap tidak kehilangan sinyal semantik. Tidak ada argumen struktural untuk dibuat di sini.

Jadi yang tersisa adalah tugas menentukan di mana harus menggantung tanda "hanya karyawan". Apa yang harus dianggap pribadi? Anda menyebutnya "getter yang masuk akal". Seperti yang telah saya katakan, pembenaran terbaik bagi seorang pengambil adalah batas yang memaksa kita menjauh dari cita-cita kita. Itu seharusnya tidak menghasilkan getter dalam segala hal. Ketika itu menghasilkan pengambil, Anda harus mempertimbangkan untuk memindahkan perilaku lebih jauh ke dalam bit yang berair di mana Anda dapat melindunginya.

Pemisahan ini telah memunculkan beberapa istilah. Objek Transfer Data atau DTO, tidak memiliki perilaku. Satu-satunya metode adalah getter dan kadang setter, kadang konstruktor. Nama ini sangat disayangkan karena itu bukan objek yang benar sama sekali. Getter dan setter hanya kode debugging yang memberi Anda tempat untuk mengatur breakpoint. Jika bukan karena kebutuhan itu, mereka hanya akan menjadi tumpukan bidang publik. Di C ++ kami biasa menyebutnya struct. Satu-satunya perbedaan yang mereka miliki dari kelas C ++ adalah mereka default ke publik.

DTO bagus karena Anda dapat melemparkannya ke dinding batas dan menjaga metode Anda lainnya dengan aman di objek perilaku berair yang bagus. Objek sejati. Tanpa getter untuk melanggar enkapsulasi itu. Objek perilaku saya dapat memakan DTO dengan menggunakannya sebagai Objek Parameter . Kadang-kadang saya harus membuat salinan defensif untuk mencegah keadaan yang dapat diubah bersama . Saya tidak menyebarkan DTO yang bisa berubah di dalam bagian berair di dalam batas. Saya merangkum mereka. Saya menyembunyikannya. Dan ketika saya akhirnya menemukan batas baru, saya memutar DTO baru dan melemparkannya ke dinding sehingga menjadikannya masalah orang lain.

Tetapi Anda ingin memberikan getter yang mengekspresikan identitas. Nah selamat Anda telah menemukan batas. Entitas memiliki identitas yang melampaui referensi mereka. Artinya, di luar alamat memori mereka. Jadi itu harus disimpan di suatu tempat. Dan sesuatu harus bisa merujuk hal ini dengan identitasnya. Seorang pengambil yang mengungkapkan identitas adalah sangat masuk akal. Setumpuk kode yang menggunakan pengambil itu untuk membuat keputusan yang bisa dibuat sendiri oleh Entitas.

Pada akhirnya bukan keberadaan getter yang salah. Mereka jauh lebih baik daripada bidang publik. Apa yang buruk adalah ketika mereka digunakan untuk berpura-pura Anda Berorientasi Objek ketika Anda tidak. Surat kabar baik. Berorientasi pada Obyek itu baik. Getters bukan Berorientasi Objek. Gunakan getter untuk mengukir tempat yang aman untuk menjadi Berorientasi Objek.

candied_orange
sumber
Inilah mengapa saya bertanya dan saya tidak yakin apakah percakapan saya terlihat dengan Robert, saya juga berusaha mencari tahu kasus tertentu di mana itu jelas menyakitkan saya untuk menggunakan "getter yang masuk akal". Saya, untuk diri saya sendiri tidak setuju dengan setter karena setidaknya untuk diri saya sendiri, sangat sulit untuk menghubungkan kepemilikan dengan tindakan seperti ini, saya biasa menggunakan setter dalam segala hal dan pada saat saya menyadari bahwa bahkan 1 setter, ketika terpengaruh oleh terlalu banyak objek membunuh saya ... saya harus menulis ulang semuanya. Penggunaan getter yang masuk akal, setelah pengujian yang mendalam untuk waktu yang lama, benar-benar tidak memiliki sisi buruk jika Anda bukan seorang purist.
coolpasta
1
@coolpasta Anda dapat membuat objek pemilik data. Objek pemilik data adalah objek data, tetapi mereka dirancang dan diberi nama sehingga mereka (jelas) memiliki data. Tentu saja benda-benda ini akan memiliki getter.
rwong
1
@rwong Apa maksudmu clearly? Jika data dikirimkan kepada saya dari sesuatu, dengan nilai , jelas, objek saya sekarang memiliki data, tetapi dengan semantik, itu belum, pada saat ini, hanya mendapatkan data dari orang lain. Kemudian harus melakukan operasi untuk mengubah data itu, menjadikannya miliknya, saat data disentuh, Anda harus membuat perubahan semantik: Anda mendapat data yang dinamai $data_from_requestdan sekarang Anda mengoperasikannya? Beri nama $changed_data. Anda ingin mengekspos data ini kepada orang lain? Buat rajin rajin getChangedRequestData, maka, kepemilikan jelas diatur. Atau itu?
coolpasta
1
"Kamu tidak bisa menulis kode yang bagus tanpa getter." Ini benar-benar salah, seperti halnya gagasan bahwa batas-batas pada dasarnya membutuhkan para pengambil. Ini bukan pragmatisme, hanya kemalasan. Agak lebih mudah untuk hanya membuang data melewati pagar dan menyelesaikannya, memikirkan kasus penggunaan dan merancang api perilaku yang baik itu sulit.
Robert Bräutigam
2
Jawaban yang sangat bagus!
cmaster - mengembalikan monica
10

Getters melanggar Prinsip Hollywood ("Jangan panggil kami, kami akan memanggilmu")

Prinsip Hollywood (alias Inversion of Control) menyatakan bahwa Anda tidak memanggil kode perpustakaan untuk menyelesaikan sesuatu; melainkan, kerangka kerja memanggil kode Anda. Karena kerangka kerja mengontrol berbagai hal, menyiarkan keadaan internal kepada kliennya tidak perlu. Anda tidak perlu tahu.

Dalam bentuknya yang paling berbahaya, melanggar Prinsip Hollywood berarti Anda menggunakan pengambil untuk mendapatkan informasi tentang keadaan suatu kelas, dan kemudian membuat keputusan tentang metode apa untuk memanggil kelas itu berdasarkan nilai yang Anda peroleh. itu merupakan pelanggaran enkapsulasi yang terbaik.

Menggunakan rajin rajin berarti bahwa Anda membutuhkan nilai itu, padahal sebenarnya tidak.

Anda mungkin benar-benar membutuhkan peningkatan kinerja itu

Dalam kasus ekstrim benda ringan yang harus memiliki kinerja semaksimal mungkin, dimungkinkan (meskipun sangat tidak mungkin) bahwa Anda tidak dapat membayar penalti kinerja sangat kecil yang dikenakan oleh seorang pengambil. Ini tidak akan terjadi 99,9 persen setiap saat.

Robert Harvey
sumber
1
Saya mengerti dan saya akan terbang dengan kebenaran Anda, bahwa saya tidak perlu tahu. . Tetapi saya telah mencapai tempat di mana saya perlu. Saya memiliki Generatorobjek yang melewati semua Itemsobjek saya , lalu memanggil getNamedari masing Item- masing untuk melakukan sesuatu lebih lanjut. Apa masalahnya dengan ini? Kemudian, sebagai balasannya, Generatormeludahkan string yang diformat. Ini ada di dalam kerangka kerja saya, yang untuknya saya memiliki API di atasnya yang dapat digunakan orang untuk menjalankan apa pun yang disediakan pengguna tetapi tanpa menyentuh kerangka itu.
coolpasta
3
What is the issue with this?Tidak ada yang bisa saya lihat. Pada dasarnya itulah yang mapdilakukan fungsi. Tapi itu bukan pertanyaan yang Anda ajukan. Anda pada dasarnya bertanya "Apakah ada setiap kondisi di mana pengambil mungkin tidak disarankan." Saya menjawab dengan dua, tetapi itu tidak berarti Anda meninggalkan setter sama sekali.
Robert Harvey
1
Anda menanyakan pertanyaan yang salah kepada orang itu. Saya seorang pragmatis; Saya melakukan apa pun yang paling sesuai dengan program khusus saya, dan tidak menaruh banyak "prinsip" kecuali mereka melayani tujuan saya.
Robert Harvey
2
@ jpmc26: Kerangka kerja. Bukan perpustakaan.
Robert Harvey
2
Kerangka kerja adalah upaya untuk mengubah bahasa tujuan umum menjadi domain khusus. Perpustakaan adalah kumpulan dari algoritma yang dapat digunakan kembali. Salah satu akan meminta Anda untuk bergantung padanya. Terserah Anda jika Anda ingin hard code baik ketergantungan atau membuat ketergantungan mudah diganti.
candied_orange
2

Rincian Implementasi Kebocoran Getters dan Break Abstraction

Mempertimbangkan public int millisecondsSince1970()

Klien Anda akan berpikir "oh, ini int" dan akan ada trilyunan panggilan dengan asumsi bahwa int , melakukan perhitungan integer, membandingkan tanggal, dll ... Ketika Anda menyadari bahwa Anda perlu waktu lama , akan ada banyak kode warisan dengan masalah. Di dunia Java, Anda akan menambahkan @deprecatedke API, semua orang akan mengabaikannya, dan Anda terjebak mempertahankan kode usang dan buggy. :-( (Saya menganggap bahasa lain mirip!)

Dalam kasus khusus ini, saya tidak yakin apa pilihan yang lebih baik, dan jawaban @candiedorange benar-benar tepat, ada banyak waktu ketika Anda membutuhkan getter, tetapi contoh ini menggambarkan kelemahannya. Setiap pengambil publik cenderung "mengunci" Anda ke dalam implementasi tertentu. Gunakan mereka jika Anda benar-benar perlu "melintasi batas", tetapi gunakan sesedikit mungkin dan dengan hati-hati dan pikiran yang matang.

pengguna949300
sumber
Ini benar, tetapi apa solusi pola untuk menegakkan tipe data / struktur ke variabel objek, juga untuk apa pun yang menggunakan pengambil untuk variabel itu?
coolpasta
1
Contoh ini menggambarkan fenomena berbeda, obsesi primitif. Saat ini sebagian besar perpustakaan dan kerangka kerja memiliki kelas yang mewakili timepointdan timespanmasing - masing. ( epochadalah nilai tertentu dari timepoint.) Pada kelas-kelas ini, mereka menyediakan getter seperti getIntatau getLongatau getDouble. Jika kelas yang memanipulasi waktu ditulis sehingga mereka (1) mendelegasikan aritmatika yang berkaitan dengan waktu ke objek dan metode ini, dan (2) memberikan akses ke objek waktu ini melalui pengambil, maka masalahnya diselesaikan, tanpa perlu menyingkirkan pengambil .
rwong
1
Untuk meringkas, getter adalah bagian dari API, dan karenanya getter perlu dirancang dengan pertimbangan yang memadai untuk semua konsekuensi, termasuk yang lalu, saat ini, dan yang akan datang. Tapi itu tidak mengarah pada kesimpulan untuk menghindari atau meminimalkan jumlah getter. Bahkan, jika ada kebutuhan di masa depan untuk mengakses sepotong informasi tertentu yang pengambil dihapus, itu akan membutuhkan perubahan API sisi perpustakaan dan perubahan kode. Dengan demikian, keputusan apakah pengambil tertentu harus dilaksanakan atau dihindari harus didasarkan pada domain dan niat, bukan pada alasan pencegahan.
rwong
1
"millisecondsSince1970" berhenti bekerja untuk int 32 bit sebelum akhir Januari 1970, jadi saya ragu akan ada banyak kode yang menggunakannya :-)
gnasher729
1
@rwong Agak benar, tetapi Anda menganggap bahwa perpustakaan pilihan yang mewakili titik waktu stabil. Yang mana tidak. Misalnya moment.js
user949300
1

Saya pikir kunci pertama adalah untuk mengingat bahwa yang absolut selalu salah.

Pertimbangkan program buku alamat, yang hanya menyimpan informasi kontak orang. Tapi, mari kita lakukan dengan benar dan memecahnya menjadi lapisan pengontrol / layanan / repositori.

Akan ada Personkelas yang menyimpan data aktual: nama, alamat, nomor telepon, dll. AddressDan Phonejuga kelas, jadi kita bisa menggunakan polimorfisme nanti untuk mendukung skema non-AS. Ketiga kelas tersebut adalah Object Transfer Data , jadi mereka tidak akan menjadi pengambil dan penentu. Dan, itu masuk akal: mereka tidak akan memiliki logika di dalamnya melampaui menimpa equalsdan getHashcode; meminta mereka memberi Anda representasi informasi orang penuh tidak masuk akal: apakah itu untuk presentasi HTML, aplikasi GUI khusus, aplikasi konsol, titik akhir HTTP, dll?

Di situlah controller, layanan, dan repositori masuk. Semua kelas-kelas itu akan menjadi logika-berat dan pengambil-cahaya, berkat injeksi ketergantungan.

Pengontrol akan mendapatkan layanan yang disuntikkan, yang akan memaparkan metode seperti getdan save, keduanya akan mengambil beberapa argumen yang masuk akal (mis., getMungkin memiliki penggantian untuk mencari berdasarkan nama, mencari dengan kode pos, atau hanya mendapatkan semuanya; savemungkin akan mengambil satu Persondan simpan). Apa getter yang dimiliki pengontrol? Mampu mendapatkan nama kelas yang konkret mungkin berguna untuk logging, tetapi status apa yang akan dipegangnya selain dari status yang telah disuntikkan ke dalamnya?

Demikian pula, lapisan layanan akan mendapatkan repositori yang disuntikkan, sehingga ia dapat benar-benar mendapatkan dan bertahan Person, dan mungkin memiliki beberapa "logika bisnis" (mis., Mungkin kita akan mengharuskan semua Personobjek memiliki setidaknya satu alamat atau telepon jumlah). Tapi, sekali lagi: keadaan apa yang dimiliki benda itu selain dari yang disuntikkan? Sekali lagi, tidak ada.

Lapisan repositori adalah tempat segala hal menjadi sedikit lebih menarik: itu akan membuat koneksi ke lokasi penyimpanan, misalnya. file, database SQL, atau penyimpanan di memori. Sangat menggoda, di sini, untuk menambahkan pengambil untuk mendapatkan nama file atau string koneksi SQL, tapi itu keadaan yang telah disuntikkan ke dalam kelas. Haruskah repositori mempunyai pengambil untuk mengetahui apakah ia berhasil terhubung ke penyimpanan datanya atau tidak? Yah, mungkin, tapi apa gunanya informasi di luar kelas repositori itu sendiri? Kelas repositori itu sendiri harus dapat mencoba untuk menyambung kembali ke penyimpanan datanya jika perlu, yang menunjukkan bahwa isConnectedproperti sudah bernilai meragukan. Lebih jauh, sebuah isConnectedproperti mungkin akan salah hanya ketika itu paling benar: memeriksaisConnectedsebelum mencoba untuk mendapatkan / menyimpan data tidak menjamin bahwa repositori masih akan terhubung ketika panggilan "nyata" dibuat, jadi itu tidak menghilangkan kebutuhan untuk penanganan pengecualian di suatu tempat (ada argumen di mana harus pergi, di luar ruang lingkup pertanyaan ini).

Pertimbangkan juga tes unit (Anda menulis tes unit, kan?): Layanan tidak akan mengharapkan kelas tertentu disuntikkan, melainkan akan berharap bahwa implementasi konkret antarmuka disuntikkan. Itu memungkinkan aplikasi sebagai perubahan menyeluruh di mana data disimpan tanpa harus melakukan apa pun selain menukar repositori yang disuntikkan ke dalam layanan. Ini juga memungkinkan layanan untuk diuji unit dengan menyuntikkan repositori tiruan. Ini berarti berpikir dalam hal antarmuka daripada kelas. Apakah antarmuka repositori memperlihatkan getter? Yaitu, apakah ada keadaan internal yang akan: umum untuk semua repositori, berguna di luar repositori, dan tidak disuntikkan ke repositori? Saya akan kesulitan untuk memikirkan diri saya sendiri.

TL; DR

Kesimpulannya: selain dari kelas-kelas yang tujuan utamanya adalah untuk membawa data, tidak ada hal lain dalam stack yang memiliki tempat untuk mendapatkan pengambil: status disuntikkan atau tidak relevan di luar kelas pekerja.

minnmass
sumber
Saya menemukan garis pemikiran ini sangat mirip dengan perdebatan tentang penggunaan properti C # yang tepat. Singkatnya, properti (yang bisa hanya rajin giat atau rajin giat) diharapkan untuk menegakkan kontrak tertentu, seperti "apa yang Anda tetapkan adalah apa yang Anda dapatkan", "rajin rajin kebanyakan bebas efek samping", "pengambil harus menghindari kesalahan melempar", dll. Berlawanan dengan kesimpulan Anda, ada banyak status objek yang bermanfaat untuk diekspos sebagai properti (atau pengambil). Contohnya terlalu banyak untuk dikutip di sini.
rwong
2
@ rwong Saya akan tertarik untuk mengetahui beberapa contoh, katakanlah untuk aplikasi "normal" "enterprise" yang dilaksanakan oleh satu tim. Mari kita asumsikan juga demi kesederhanaan, tidak ada pihak ketiga yang terlibat. Anda tahu, sistem mandiri, seperti Kalender, toko hewan peliharaan, apa pun yang Anda inginkan.
Robert Bräutigam
1

Apa satu hal, tanpa pendapat, yang akan rusak jika saya menggunakan getter secara masuk akal dan untuk data yang jelas integritas objeknya tidak pecah jika dipadamkan?

Anggota yang bisa berubah-ubah.

Jika Anda memiliki koleksi hal-hal dalam objek yang Anda paparkan melalui pengambil, Anda berpotensi mengekspos diri Anda untuk bug yang terkait dengan hal-hal yang salah ditambahkan ke dalam koleksi.

Jika Anda memiliki objek yang bisa berubah yang Anda tampilkan melalui pengambil, Anda berpotensi membuka diri hingga keadaan internal objek Anda diubah dengan cara yang tidak Anda harapkan.

Contoh yang sangat buruk adalah objek yang menghitung dari 1 hingga 100 yang memperlihatkan nilai saat ini sebagai referensi yang bisa berubah. Ini memungkinkan objek pihak ketiga untuk mengubah nilai Current sedemikian rupa sehingga nilainya bisa berada di luar batas yang diharapkan.

Ini sebagian besar masalah dengan mengekspos objek yang bisa berubah. Paparan struct atau objek yang tidak berubah sama sekali bukan masalah, karena perubahan apa pun pada mereka akan mengubah salinan sebagai gantinya (biasanya baik dengan salinan implisit dalam kasus struct atau dengan salinan eksplisit dalam kasus objek yang tidak dapat diubah).

Untuk menggunakan metafora yang mungkin membuatnya lebih mudah untuk melihat perbedaannya.

Bunga memiliki sejumlah hal yang unik tentangnya. Ia memiliki Colordan memiliki sejumlah kelopak (NumPetals). Jika saya mengamati bunga itu, di dunia nyata, saya dapat dengan jelas melihat warnanya. Saya kemudian dapat membuat keputusan berdasarkan warna itu. Misalnya, jika warna hitam, jangan berikan kepada pacar tetapi jika warna merah, berikan kepada pacar. Dalam model objek kami, warna bunga akan diekspos sebagai pengambil pada objek bunga. Pengamatan saya tentang warna itu penting untuk tindakan yang akan saya lakukan, tetapi tidak berdampak sama sekali pada objek bunga. Seharusnya aku tidak bisa mengubah warna bunga itu. Sama, tidak masuk akal untuk menyembunyikan properti warna. Bunga umumnya tidak dapat mencegah orang dari mengamati warnanya.

Jika saya mewarnai bunga, saya harus memanggil metode ReactToDye (Color dyeColor) pada bunga, yang akan mengubah bunga sesuai dengan aturan internalnya. Saya kemudian dapat meminta Colorproperti lagi dan bereaksi terhadap perubahan di dalamnya setelah metode ReactToDye dipanggil. Akan salah bagi saya untuk secara langsung memodifikasi Colorbunga dan jika saya bisa maka abstraksi telah rusak.

Terkadang (lebih jarang, tetapi masih cukup sering sehingga layak disebut) setter adalah desain OO yang cukup valid. Jika saya memiliki objek Pelanggan, cukup valid untuk mengekspos setter untuk alamat mereka. Apakah Anda menyebutnya bahwa setAddress(string address)atau ChangeMyAddressBecauseIMoved(string newAddress)atau hanya string Address { get; set; }merupakan masalah semantik. Keadaan internal objek itu perlu diubah dan cara yang tepat untuk melakukannya adalah mengatur keadaan internal objek itu. Bahkan jika saya memerlukan catatan sejarah alamat tempat Customertinggal, saya dapat menggunakan setter untuk mengubah keadaan internal saya secara tepat untuk melakukannya. Dalam hal ini tidak masuk akal bagi orang yang Customertidak dapat berubah dan tidak ada cara yang lebih baik untuk mengubah alamat daripada menyediakan setter untuk melakukannya.

Saya tidak yakin siapa yang menyarankan bahwa Getters dan setter adalah paradigma berorientasi objek yang buruk atau rusak, tetapi jika mereka melakukannya, mereka mungkin melakukannya sebagai respons terhadap fitur bahasa tertentu dari bahasa yang mereka gunakan. Saya merasa bahwa ini tumbuh dari Jawa "semuanya adalah objek" budaya (dan mungkin diperluas ke beberapa bahasa lain). Dunia .NET tidak memiliki diskusi ini sama sekali. Getters and Setters adalah fitur bahasa kelas satu yang digunakan tidak hanya oleh orang yang menulis aplikasi dalam bahasa, tetapi juga oleh API bahasa itu sendiri.

Anda harus berhati-hati saat menggunakan getter. Anda tidak ingin mengekspos bagian data yang salah dan Anda juga tidak ingin mengekspos data dengan cara yang salah (yaitu objek yang bisa berubah, referensi ke struct yang dapat memungkinkan konsumen untuk mengubah keadaan internal). Tetapi Anda ingin memodelkan objek Anda sehingga data dienkapsulasi sedemikian rupa sehingga objek Anda dapat digunakan oleh konsumen eksternal dan dilindungi dari penyalahgunaan oleh konsumen yang sama. Seringkali yang membutuhkan getter.

Untuk meringkas: Getters dan Setters adalah alat desain berorientasi objek yang valid. Mereka tidak dapat digunakan secara bebas sehingga setiap detail implementasi diekspos tetapi Anda juga tidak ingin menggunakannya dengan hemat sehingga konsumen objek tidak dapat menggunakan objek secara efisien.

Stephen
sumber
-1

Apa satu hal, tanpa pendapat, yang akan rusak jika saya menggunakan getter ...

Pemeliharaan akan pecah.

Kapan saja (saya harus mengatakan hampir selalu) Anda menawarkan kepada pengambil Anda pada dasarnya Anda memberikan lebih dari yang diminta dari Anda. Ini juga berarti bahwa Anda harus mempertahankan lebih dari yang diminta, sehingga Anda menurunkan tingkat perawatan tanpa alasan yang nyata.

Mari kita pergi dengan Collectioncontoh @ candied_orange . Bertentangan dengan apa yang ia tulis, Collection seharusnya tidak ada yang rajin giat. Koleksi ada karena alasan yang sangat spesifik, terutama untuk beralih ke semua item. Fungsionalitas ini bukan kejutan bagi siapa pun, jadi itu harus diimplementasikan dalam Collection, alih-alih mendorong use-case yang jelas ini pada pengguna, menggunakan for-cycle dan getter atau yang lainnya.

Agar adil, beberapa batasan memang membutuhkan getter. Ini terjadi jika Anda benar-benar tidak tahu akan digunakan untuk apa mereka. Sebagai contoh, Anda dapat secara pemrograman mendapatkan stacktrace dari Exceptionkelas Java saat ini, karena orang ingin menggunakannya untuk segala macam alasan aneh yang tidak atau tidak bisa dibayangkan oleh penulis.

Robert Bräutigam
sumber
1
Contoh tandingan. Pertimbangkan fungsi yang perlu mengulang dua Collections secara bersamaan, seperti pada (A1, B1), (A2, B2), .... Ini membutuhkan implementasi "zip". Bagaimana Anda menerapkan "zip" jika fungsi iterate-over diimplementasikan pada salah satu dari dua Collection- bagaimana Anda mengakses item yang sesuai di yang lain?
rwong
@ rwong Collectionharus menerapkan zipdengan sendirinya, tergantung bagaimana perpustakaan ditulis. Jika tidak, Anda menerapkannya dan mengirimkan permintaan tarik ke pembuat perpustakaan. Perhatikan bahwa saya setuju bahwa beberapa batasan terkadang membutuhkan getter, masalah sebenarnya saya adalah getter ada di mana-mana saat ini.
Robert Bräutigam
Dalam hal itu, itu menyiratkan bahwa perpustakaan harus memiliki getter pada Collectionobjek, setidaknya untuk implementasi sendiri zip. (Artinya, rajin rajin harus memiliki visibilitas paket paling tidak.) Dan sekarang Anda bergantung pada pembuat perpustakaan yang menerima permintaan tarik Anda ...
rwong
Saya tidak mengerti Anda. The Collectionjelas dapat mengakses keadaan internal sendiri, atau lebih tepatnya setiap Collectioninstance dapat mengakses keadaan internal setiap lain. Itu jenis yang sama, tidak perlu getter.
Robert Bräutigam
Saya mendengar Anda juga, tetapi sekali lagi, apa sebenarnya solusi yang lebih baik untuk getter? Saya tahu itu di luar cakupan pertanyaan.
coolpasta