Memiliki rantai yang diimplementasikan pada kacang sangat berguna: tidak perlu untuk membebani konstruktor, konstruktor besar, pabrik, dan memberi Anda peningkatan keterbacaan. Saya tidak bisa memikirkan kelemahan, kecuali jika Anda ingin objek Anda tidak berubah , dalam hal ini tidak akan memiliki setter. Jadi adakah alasan mengapa ini bukan konvensi OOP?
public class DTO {
private String foo;
private String bar;
public String getFoo() {
return foo;
}
public String getBar() {
return bar;
}
public DTO setFoo(String foo) {
this.foo = foo;
return this;
}
public DTO setBar(String bar) {
this.bar = bar;
return this;
}
}
//...//
DTO dto = new DTO().setFoo("foo").setBar("bar");
myCustomDTO = DTOBuilder.defaultDTO().withFoo("foo").withBar("bar").Build();
Saya akan melakukannya, agar tidak bertentangan dengan gagasan umum bahwa setter kosong.new Foo().setBar('bar').setBaz('baz')
terasa sangat "lancar". Maksudku, tentu saja bisa diimplementasikan dengan cara yang persis sama, tetapi saya sangat berharap untuk membaca sesuatu yang lebih miripFoo().barsThe('bar').withThe('baz').andQuuxes('the quux')
Jawaban:
Tebakan terbaik saya: karena melanggar CQS
Anda telah mendapat perintah (mengubah status objek) dan kueri (mengembalikan salinan status - dalam hal ini, objek itu sendiri) dicampur ke dalam metode yang sama. Itu tidak selalu menjadi masalah, tetapi itu melanggar beberapa pedoman dasar.
Misalnya, dalam C ++, std :: stack :: pop () adalah perintah yang mengembalikan void, dan std :: stack :: top () adalah kueri yang mengembalikan referensi ke elemen teratas di stack. Klasik, Anda ingin menggabungkan keduanya, tetapi Anda tidak bisa melakukan itu dan menjadi pengecualian aman. (Tidak masalah di Jawa, karena operator penugasan di Jawa tidak melempar).
Jika DTO adalah tipe nilai, Anda mungkin mencapai akhir yang sama dengannya
Juga, merantai nilai kembali adalah rasa sakit yang luar biasa ketika Anda berurusan dengan warisan. Lihat "Pola templat berulang yang aneh"
Akhirnya, ada masalah bahwa konstruktor default harus meninggalkan Anda dengan objek yang dalam keadaan valid. Jika Anda harus menjalankan banyak perintah untuk mengembalikan objek ke status yang valid, ada yang salah.
sumber
abstract
T getSelf()
metode dengan mengembalikan tipe generik. Sekarang, alih-alih kembalithis
dari setter Anda, Andareturn getSelf()
dan kemudian setiap kelas utama hanya membuat tipe generik dalam dirinya sendiri dan kembalithis
darigetSelf
. Dengan cara ini setter mengembalikan tipe aktual dan bukan tipe deklarasi.Menyimpan beberapa penekanan tombol tidak menarik. Mungkin bagus, tetapi konvensi OOP lebih peduli pada konsep dan struktur, bukan penekanan tombol.
Nilai kembali tidak ada artinya.
Bahkan lebih daripada menjadi tidak berarti, nilai kembali menyesatkan, karena pengguna dapat mengharapkan nilai kembali memiliki arti. Mereka mungkin berharap bahwa itu adalah "penyetel abadi"
Pada kenyataannya, setter Anda mengubah objek.
Itu tidak bekerja dengan baik dengan warisan.
Saya bisa menulis
tapi tidak
Bagi saya, # 1 hingga # 3 adalah yang penting. Kode yang ditulis dengan baik bukan tentang teks yang disusun dengan menyenangkan. Kode yang ditulis dengan baik adalah tentang konsep, hubungan, dan struktur dasar. Teks hanyalah refleksi luar dari arti sebenarnya dari kode.
sumber
public class Foo<T extends Foo> {...}
dengan setter kembaliFoo<T>
. Juga metode 'setter' itu, saya lebih suka menyebutnya metode 'dengan'. Jika kelebihan beban bekerja dengan baik, maka adilFoo<T> with(Bar b) {...}
, jika tidakFoo<T> withBar(Bar b)
.Saya tidak berpikir ini adalah konvensi OOP, ini lebih terkait dengan desain bahasa dan konvensi.
Sepertinya Anda suka menggunakan Java. Java memiliki spesifikasi JavaBeans yang menentukan tipe pengembalian setter yang batal, yaitu bertentangan dengan rantai setter. Spesifikasi ini diterima secara luas dan diimplementasikan dalam berbagai alat.
Tentu saja Anda mungkin bertanya, mengapa tidak merantai bagian dari spesifikasinya. Saya tidak tahu jawabannya, mungkin pola ini tidak dikenal / populer saat itu.
sumber
Object
, yang dapat mengakibatkan singleton tipeVoid
dikembalikan jika metode menentukanvoid
sebagai tipe pengembaliannya. Dalam berita lain, tampaknya "meninggalkan komentar tetapi tidak memberikan suara" adalah alasan untuk kegagalan audit "posting pertama" meskipun itu adalah komentar yang baik. Saya menyalahkan shog untuk ini.Seperti yang dikatakan orang lain, ini sering disebut antarmuka yang lancar .
Biasanya setter adalah panggilan lewat variabel sebagai respons terhadap kode logika dalam aplikasi; kelas DTO Anda adalah contohnya. Kode konvensional ketika setter tidak mengembalikan apa pun adalah yang terbaik untuk ini. Jawaban lain telah menjelaskan caranya.
Namun ada beberapa kasus di mana antarmuka yang lancar mungkin merupakan solusi yang baik, ini memiliki kesamaan.
Menyiapkan konfigurasi, misalnya fasih-nhibernate
Menyiapkan data uji dalam unit test, menggunakan TestDataBulderClasses khusus (Object Mothers)
Namun menciptakan antarmuka yang lancar sangat sulit , jadi itu hanya layak jika Anda memiliki banyak pengaturan "statis". Juga antarmuka yang lancar tidak boleh dicampur dengan kelas "normal"; karenanya pola pembangun sering digunakan.
sumber
Saya pikir banyak alasan itu bukan konvensi untuk rantai satu setter demi satu karena untuk kasus-kasus itu lebih khas untuk melihat objek opsi atau parameter dalam konstruktor. C # memiliki sintaks initializer juga.
Dari pada:
Orang mungkin menulis:
(dalam JS)
(dalam C #)
(di Jawa)
setFoo
dansetBar
kemudian tidak lagi diperlukan untuk inisialisasi, dan dapat digunakan untuk mutasi nanti.Sementara chainability berguna dalam beberapa keadaan, penting untuk tidak mencoba memasukkan semuanya dalam satu baris hanya demi mengurangi karakter baris baru.
Sebagai contoh
membuatnya lebih sulit untuk membaca dan memahami apa yang terjadi. Memformat ulang ke:
Jauh lebih mudah dipahami, dan membuat "kesalahan" di versi pertama lebih jelas. Setelah Anda refactored kode ke format itu, tidak ada keuntungan nyata dari:
sumber
/
untuk mewakili jeda baris]With Foo(1234) / .x = 23 / .y = 47
akan setara denganDim temp=Foo(1234) / temp.x = 23 / temp.y = 47
. Sintaks semacam itu tidak menciptakan ambiguitas karena.x
dengan sendirinya tidak dapat memiliki makna selain untuk mengikat ke pernyataan "With" yang langsung mengelilingi [jika tidak ada, atau objek tidak memiliki anggotax
, maka.x
tidak ada artinya]. Oracle belum memasukkan hal seperti itu di Jawa, tetapi konstruksi seperti itu akan cocok dengan lancar dalam bahasa.Teknik itu sebenarnya digunakan dalam pola Builder.
Namun, secara umum hal itu dihindari karena bersifat rancu. Tidak jelas apakah nilai kembali adalah objek (sehingga Anda dapat memanggil setter lain), atau jika objek kembali adalah nilai yang baru saja ditetapkan (juga merupakan pola umum). Dengan demikian, Prinsip Terkecil Least menyarankan Anda tidak boleh mencoba menganggap pengguna ingin melihat satu solusi atau yang lain, kecuali itu mendasar untuk desain objek.
sumber
Obj* x = doSomethingToObjAndReturnIt(new Obj(1, 2, 3));
saya pikir itu juga mendapatkan popularitas karena itu mencerminkana = b = c = d
, meskipun saya tidak yakin bahwa popularitas beralasan. Saya telah melihat yang Anda sebutkan, mengembalikan nilai sebelumnya, di beberapa perpustakaan operasi atom. Pesan moral dalam cerita? Ini bahkan lebih membingungkan daripada yang saya buat terdengar =)new BetterText(string).indent(4).box().print();
. Dalam hal ini, saya telah melewati sekelompok gobbledygook dan mengambil string, menjoroknya, mengepaknya, dan mengeluarkannya. Anda bahkan mungkin ingin metode duplikasi dalam kaskade (seperti, katakanlah.copy()
) untuk memungkinkan semua tindakan berikut tidak lagi mengubah yang asli.Ini lebih merupakan komentar daripada jawaban, tapi saya tidak bisa berkomentar, jadi ...
Saya hanya ingin mengatakan bahwa pertanyaan ini mengejutkan saya karena saya tidak melihat ini sama sekali tidak umum . Sebenarnya, di lingkungan kerja saya (pengembang web) sangat umum.
Sebagai contoh, ini adalah bagaimana perintah Symfony: menghasilkan: perintah entitas menghasilkan otomatis semua
setters
, secara default .jQuery agak rantai sebagian besar metodenya dengan cara yang sangat mirip.
sumber
JAB
. Pada tahun-tahun kuliah saya, saya digunakan untuk melihat ke bawah di JS sebagai kekejian wanna-be bahasa scripting, tetapi setelah bekerja beberapa tahun dengan itu, dan belajar KANAN cara menggunakannya, aku datang untuk ... benar-benar mencintai itu . Dan saya pikir dengan ES6 itu akan menjadi bahasa yang benar-benar matang . Tapi, apa yang membuat saya menoleh adalah ... apa jawaban saya terkait dengan JS sejak awal? ^^ U