Apakah ini ide yang baik atau buruk untuk membuat setter di java mengembalikan "ini"?
public Employee setName(String name){
this.name = name;
return this;
}
Pola ini dapat bermanfaat karena Anda dapat mengatur setter seperti ini:
list.add(new Employee().setName("Jack Sparrow").setId(1).setFoo("bacon!"));
alih-alih ini:
Employee e = new Employee();
e.setName("Jack Sparrow");
...and so on...
list.add(e);
... tapi itu agak bertentangan dengan konvensi standar. Saya kira itu mungkin bermanfaat hanya karena dapat membuat setter itu melakukan sesuatu yang bermanfaat. Saya telah melihat pola ini menggunakan beberapa tempat (misalnya JMock, JPA), tetapi tampaknya tidak umum, dan hanya umumnya digunakan untuk API yang didefinisikan dengan sangat baik di mana pola ini digunakan di mana-mana.
Memperbarui:
Apa yang saya jelaskan jelas valid, tetapi yang benar-benar saya cari adalah beberapa pemikiran tentang apakah ini secara umum dapat diterima, dan jika ada jebakan atau praktik terbaik terkait. Saya tahu tentang pola Builder tetapi sedikit lebih terlibat daripada apa yang saya jelaskan - seperti yang dijelaskan oleh Josh Bloch, ada kelas Builder statis terkait untuk pembuatan objek.
sumber
this
. Kadang-kadang, saya bahkan mengubah fungsi sehingga alih-alih mengembalikan nilai, itu beroperasi pada anggota objek, supaya saya bisa melakukan ini. Itu luar biasa. :)Jawaban:
Saya tidak berpikir ada sesuatu yang salah dengan itu, itu hanya masalah gaya. Ini berguna saat:
Alternatif untuk metode ini mungkin:
Jika Anda hanya akan menetapkan beberapa properti pada satu waktu saya akan mengatakan itu tidak layak mengembalikan 'ini'. Itu pasti jatuh jika Anda kemudian memutuskan untuk mengembalikan sesuatu yang lain, seperti status / indikator keberhasilan / pesan.
sumber
Itu bukan praktik yang buruk. Ini adalah praktik yang semakin umum. Sebagian besar bahasa tidak mengharuskan Anda untuk berurusan dengan objek yang dikembalikan jika Anda tidak ingin sehingga itu tidak mengubah sintaks penggunaan setter "normal" tetapi memungkinkan Anda untuk rantai setter bersama-sama.
Ini biasa disebut pola pembangun atau antarmuka yang lancar .
Ini juga umum di API Java:
sumber
bla.foo.setBar1(...) ; bla.foo.setBar2(...)
ketika Anda bisa menulisbla.foo /* newline indented */.setBar1(...) /* underneath previous setter */ .setBar2(...)
(tidak dapat menggunakan linebreak dalam komentar SO seperti ini :-( ... harap Anda mendapatkan intinya dengan mempertimbangkan 10 setter atau panggilan yang lebih kompleks)Untuk meringkas:
Beberapa poin lain yang tidak disebutkan:
Ini melanggar prinsip bahwa setiap fungsi harus melakukan satu (dan hanya satu) hal. Anda mungkin atau mungkin tidak percaya pada hal ini, tetapi di Jawa saya percaya itu bekerja dengan baik.
IDE tidak akan menghasilkan ini untuk Anda (secara default).
Saya akhirnya, inilah titik data dunia nyata. Saya punya masalah menggunakan perpustakaan yang dibangun seperti ini. Pembuat kueri Hibernate adalah contohnya di pustaka yang ada. Karena metode set * Query mengembalikan kueri, mustahil untuk mengetahui hanya dengan melihat tanda tangan bagaimana menggunakannya. Sebagai contoh:
Ini memperkenalkan ambiguitas: apakah metode memodifikasi objek saat ini (pola Anda) atau, mungkin Query benar-benar abadi (pola yang sangat populer dan berharga), dan metode ini mengembalikan yang baru. Itu hanya membuat perpustakaan lebih sulit untuk digunakan, dan banyak programmer tidak memanfaatkan fitur ini. Jika setter adalah setter, akan lebih jelas bagaimana menggunakannya.
sumber
this
bukanlah ilmu roket yang rumit. :-)Saya lebih suka menggunakan metode 'dengan' untuk ini:
Jadi:
Peringatan :
withX
sintaks ini biasanya digunakan untuk menyediakan "setter" untuk objek yang tidak dapat diubah, jadi penelepon dari metode ini mungkin mengharapkan mereka untuk membuat objek baru daripada bermutasi pada instance yang ada. Mungkin kata-kata yang lebih masuk akal adalah sesuatu seperti:Dengan konvensi penamaan chainsetXyz () hampir semua orang pasti senang.
sumber
get
,,set
danwith
untuk setiap bidang kelas. Ini masih merupakan solusi yang menarik. :)Project Lombok
's@Getter/@Setter
penjelasan ... yang akan fantastis untuk chaining. Atau Anda bisa menggunakan sesuatu yang sangat mirip denganKestrel
kombinator ( github.com/raganwald/Katy ) yang digunakan oleh JQuery dan Javascript.with
prefix adalah konvensi yang berbeda. sebagai @qualidafial memberi contoh. metode yang diawali denganwith
seharusnya tidak mengembalikanthis
tetapi lebih sebagai contoh baru seperti contoh saat ini tetapiwith
perubahan itu. Ini dilakukan ketika Anda ingin benda Anda tidak berubah. Jadi ketika saya melihat metode diawali denganwith
saya berasumsi saya akan mendapatkan objek baru, bukan objek yang sama.Jika Anda tidak ingin kembali
'this'
dari setter tetapi tidak ingin menggunakan opsi kedua, Anda dapat menggunakan sintaks berikut untuk mengatur properti:Sebagai tambahan saya pikir itu sedikit lebih bersih di C #:
sumber
equals
metode ini. Ada cara yang sangat bersih untuk berurusan dengan kelas anonimequals
jika Anda tahu apa yang Anda lakukan.Itu tidak hanya merusak konvensi getter / setter, tetapi juga merusak kerangka referensi metode Java 8.
MyClass::setMyValue
adalahBiConsumer<MyClass,MyValue>
, danmyInstance::setMyValue
merupakanConsumer<MyValue>
. Jika Anda memiliki setter kembalithis
, maka itu bukan lagi contoh yang validConsumer<MyValue>
, tetapi lebih dariFunction<MyValue,MyClass>
, dan akan menyebabkan apa pun menggunakan referensi metode untuk setter tersebut (dengan asumsi mereka adalah metode batal) untuk istirahat.sumber
Consumer<A>
danFunction<A,B>
dengan memberikan implementasi standarvoid accept(A a) { apply(a); }
. Maka dapat dengan mudah digunakan sebagai salah satu dan tidak akan merusak kode apa pun yang membutuhkan bentuk tertentu.Saya tidak tahu Java tapi saya sudah melakukan ini di C ++. Orang lain mengatakan itu membuat garis sangat panjang dan sangat sulit dibaca, tapi saya sudah sering melakukannya seperti ini:
Ini bahkan lebih baik:
setidaknya, saya pikir. Tapi Anda dipersilakan untuk menurunkan saya dan memanggil saya seorang programmer yang buruk jika Anda mau. Dan saya tidak tahu apakah Anda diizinkan untuk melakukan ini di Jawa.
sumber
//
setelah setiap metode jika Anda mengkonfigurasi IDE Anda untuk tidak bergabung dengan baris yang sudah dibungkus (misalnya Eclipse> Properties> Java> Style Code> Formatter> Line Wrapping> Jangan pernah bergabung dengan baris yang sudah dibungkus).Skema ini (pun intended), yang disebut 'antarmuka lancar', menjadi cukup populer sekarang. Itu bisa diterima, tapi itu bukan cangkir teh saya.
sumber
Karena tidak mengembalikan batal, itu bukan lagi setter properti JavaBean yang valid. Itu mungkin penting jika Anda salah satu dari tujuh orang di dunia menggunakan alat visual "Bean Builder", atau salah satu dari 17 orang menggunakan elemen JSP-bean-setProperty.
sumber
Setidaknya secara teori , ini dapat merusak mekanisme optimisasi JVM dengan mengatur dependensi palsu antara panggilan.
Seharusnya gula sintaksis, tetapi sebenarnya dapat membuat efek samping di mesin virtual Java 43 super-cerdas.
Itu sebabnya saya memilih tidak, jangan menggunakannya.
sumber
set
metode kedua tergantung padaset
metode pertama meskipun diketahui oleh programmer.-XX:+UnlockDiagnosticVMOptions -XX:+PrintInlining
Java7 jdk jelas sebaris metode chained, dan melakukan sekitar jumlah iterasi yang sama yang diperlukan untuk menandai setter kosong seperti panas dan sebaris pula. Berpikir Anda meremehkan kekuatan algoritma pemangkasan opcode JVM; jika ia tahu Anda mengembalikan ini, ia akan melewatkan opcode jrs (pernyataan pengembalian java) dan biarkan ini di stack.Itu sama sekali bukan praktik buruk. Tapi itu tidak kompatibel dengan JavaBeans Spec .
Dan ada banyak spesifikasi tergantung pada pengakses standar tersebut.
Anda selalu dapat membuat mereka hidup berdampingan satu sama lain.
Sekarang kita bisa menggunakannya bersama.
Di sinilah versi lain untuk objek abadi.
Sekarang kita bisa melakukan ini.
sumber
some
bidang. Kedua, Anda harus menambahkan perlindungan dan diatursome
kenull
dalam build () sehinggaSome
benar-benar tidak dapat diubah, jika tidak Anda dapat memanggilbuilder.value()
instance Builder yang sama lagi. Dan Terakhir, ya Anda memiliki pembangun, tetapi AndaSome
masih memiliki konstruktor publik, artinya Anda tidak secara terbuka menganjurkan penggunaan Builder, yaitu pengguna tidak mengetahuinya selain dengan mencoba atau mencari metode untuk menetapkan kebiasaanvalue
sama sekali.Jika Anda menggunakan konvensi yang sama di seluruh aplikasi, sepertinya tidak masalah.
Di sisi lain jika bagian yang ada dari aplikasi Anda menggunakan konvensi standar saya akan tetap menggunakannya dan menambahkan pembangun ke kelas yang lebih rumit
sumber
Paulo Abrantes menawarkan cara lain untuk membuat JavaBean setter fasih: mendefinisikan kelas pembangun batin untuk setiap JavaBean. Jika Anda menggunakan alat yang bingung oleh setter yang mengembalikan nilai, pola Paulo bisa membantu.
sumber
Saya mendukung pemukim memiliki "ini" kembali. Saya tidak peduli jika itu tidak sesuai dengan kacang. Bagi saya, jika boleh memiliki ekspresi / pernyataan "=", maka seters bahwa nilai pengembalian baik-baik saja.
sumber
Saya dulu lebih suka pendekatan ini tetapi saya telah memutuskan untuk tidak melakukannya.
Alasan:
Pola Builder yang saya lihat tidak menggunakan konvensi setFoo (foo) .setBar (bar) tetapi lebih banyak foo (foo) .bar (bar). Mungkin karena alasan-alasan itu.
Memang, seperti biasa soal selera. Saya hanya menyukai pendekatan "kejutan kecil".
sumber
Pola khusus ini disebut Metode Chaining. Tautan Wikipedia , ini memiliki lebih banyak penjelasan dan contoh bagaimana melakukannya dalam berbagai bahasa pemrograman.
PS: Baru saja berpikir untuk meninggalkannya di sini, karena saya sedang mencari nama yang spesifik.
sumber
Pada pandangan pertama: "Mengerikan!".
Dipikirkan lebih lanjut
sebenarnya lebih sedikit kesalahan daripada
Sangat menarik. Menambahkan ide ke toolbag ...
sumber
list
di awal.Ya, saya pikir itu ide yang bagus.
Jika saya bisa menambahkan sesuatu, bagaimana dengan masalah ini:
Ini akan berhasil:
Ini tidak akan diterima oleh Eclipse! :
Ini karena setName () mengembalikan Orang dan bukan Teman, dan tidak ada PeoplesetNickName.
Bagaimana kita bisa menulis setter untuk mengembalikan kelas SELF alih-alih nama kelas?
Sesuatu seperti ini akan baik-baik saja (jika kata kunci DIRI akan ada). Apakah ini ada?
sumber
class C<S extends C<S>>
, yang lebih aman daripada dataranS extends C
. a) JikaA extends B
, danB extends C<B>
, dan Anda memiliki nilai A, Anda hanya tahu bahwa B dikembalikan kecuali A menimpa masing-masing dan setiap metode. b) Anda tidak dapat menunjukkan lokal, non-mentahC<C<C<C<C<...>>>>>
.Secara umum ini adalah praktik yang baik, tetapi Anda mungkin perlu untuk fungsi tipe-set menggunakan tipe Boolean untuk menentukan apakah operasi berhasil diselesaikan atau tidak, itu juga salah satu caranya. Secara umum, tidak ada dogma untuk mengatakan bahwa ini baik atau ranjang, itu berasal dari situasi, tentu saja.
sumber
Dari pernyataan itu
saya melihat dua hal
1) Pernyataan tidak berarti. 2) Kurangnya keterbacaan.
sumber
Ini mungkin kurang mudah dibaca
atau ini
Ini jauh lebih mudah dibaca daripada:
sumber
Saya telah membuat setter saya cukup lama dan satu-satunya masalah sebenarnya adalah dengan perpustakaan yang tetap dengan getPropertyDescriptors yang ketat untuk mendapatkan aksesor pembaca kacang / penulis bean. Dalam kasus itu, "kacang" java Anda tidak akan memiliki pembungkus yang Anda harapkan.
Sebagai contoh, saya belum mengujinya dengan pasti, tetapi saya tidak akan terkejut bahwa Jackson tidak akan mengenali mereka sebagai setter ketika membuat Anda objek java dari json / maps. Saya harap saya salah dalam hal ini (saya akan segera mengujinya).
Bahkan, saya sedang mengembangkan ORM SQL sentris ringan dan saya harus menambahkan beberapa kode getPropertyDescriptors beyong ke setter diakui yang mengembalikan ini.
sumber
Dulu jawaban, tapi dua sen saya ... Tidak apa-apa. Saya berharap antarmuka yang lancar ini digunakan lebih sering.
Pengulangan variabel 'pabrik' tidak menambahkan info lebih lanjut di bawah ini:
Ini lebih bersih, ya:
Tentu saja, sebagai salah satu jawaban yang telah disebutkan, Java API harus di-tweak untuk melakukan ini dengan benar untuk beberapa situasi, seperti warisan dan alat.
sumber
Lebih baik menggunakan konstruksi bahasa lain jika tersedia. Misalnya, dalam Kotlin, Anda akan menggunakan dengan , menerapkan , atau biarkan . Jika menggunakan pendekatan ini, Anda tidak perlu mengembalikan instance dari setter Anda.
Pendekatan ini memungkinkan kode klien Anda menjadi:
Berikut ini beberapa contohnya.
sumber
Jika saya menulis API, saya menggunakan "kembalikan ini" untuk menetapkan nilai yang hanya akan ditetapkan satu kali. Jika saya memiliki nilai lain yang harus dapat diubah oleh pengguna, saya menggunakan setter void standar sebagai gantinya.
Namun, itu benar-benar masalah preferensi dan pengaturan rantai memang terlihat cukup keren, menurut saya.
sumber
Saya setuju dengan semua poster yang mengklaim bahwa ini melanggar spesifikasi JavaBeans. Ada alasan untuk melestarikan itu, tetapi saya juga merasa bahwa penggunaan Pola Pembangun ini (yang disinggung) memiliki tempatnya; selama itu tidak digunakan di mana-mana, itu harus dapat diterima. "It's Place", bagi saya, adalah titik akhir panggilan untuk metode "build ()".
Ada cara lain untuk mengatur semua hal ini tentu saja, tetapi keuntungan di sini adalah bahwa ia menghindari 1) banyak konstruktor publik parameter dan 2) objek yang ditentukan sebagian. Di sini, Anda memiliki pembangun mengumpulkan apa yang dibutuhkan dan kemudian memanggilnya "build ()" di akhir, yang kemudian dapat memastikan bahwa objek yang ditentukan sebagian tidak dibangun, karena operasi itu dapat diberikan visibilitas kurang dari-publik. Alternatifnya adalah "objek parameter", tetapi IMHO hanya mendorong masalah kembali satu tingkat.
Saya tidak suka konstruktor banyak-parameter karena mereka membuatnya lebih mungkin bahwa banyak argumen tipe-sama diteruskan, yang dapat membuatnya lebih mudah untuk menyampaikan argumen yang salah ke parameter. Saya tidak suka menggunakan banyak setter karena objek dapat digunakan sebelum sepenuhnya dikonfigurasi. Selanjutnya, gagasan memiliki nilai default berdasarkan pilihan sebelumnya lebih baik disajikan dengan metode "build ()".
Singkatnya, saya pikir ini adalah praktik yang baik, jika digunakan dengan benar.
sumber
Kebiasaan buruk: seorang setter mengatur getter get
bagaimana dengan mendeklarasikan metode secara eksplisit, yang melakukannya untuk U
sumber