Saya memiliki beberapa objek besar (lebih dari 3 bidang) yang dapat dan harus tetap. Setiap kali saya mengalami kasus itu saya cenderung membuat kekejian konstruktor dengan daftar parameter yang panjang.
Rasanya tidak benar, sulit digunakan, dan sulit dibaca.
Lebih buruk lagi jika bidang adalah semacam jenis koleksi seperti daftar. Sederhana addSibling(S s)
akan sangat memudahkan pembuatan objek tetapi membuat objek bisa berubah.
Apa yang kalian gunakan dalam kasus seperti itu?
Saya menggunakan Scala dan Java, tapi menurut saya masalahnya adalah bahasa agnostik selama bahasanya berorientasi objek.
Solusi yang dapat saya pikirkan:
- "Kekejian konstruktor dengan daftar parameter yang panjang"
- Pola Pembangun
java
oop
scala
immutability
Malax
sumber
sumber
Jawaban:
Nah, Anda ingin objek yang lebih mudah dibaca dan tidak dapat diubah setelah dibuat?
Saya pikir antarmuka yang lancar DILAKUKAN DENGAN BENAR akan membantu Anda.
Ini akan terlihat seperti ini (contoh yang dibuat murni):
Saya menulis "SELESAI DENGAN BENAR" dengan huruf tebal karena sebagian besar programmer Java salah menggunakan antarmuka yang fasih dan mencemari objek mereka dengan metode yang diperlukan untuk membangun objek, yang tentu saja sepenuhnya salah.
Triknya adalah hanya metode build () yang benar-benar membuat Foo (karena itu Foo Anda tidak dapat diubah).
FooFactory.create () , di manaXXX (..) dan withXXX (..) semuanya menciptakan "sesuatu yang lain".
Bahwa sesuatu yang lain mungkin FooFactory, inilah salah satu cara untuk melakukannya ....
Anda FooFactory akan terlihat seperti ini:
sumber
Foo
objek, daripada harus terpisahFooFactory
.FooImpl
konstruktor dengan 8 parameter. Apa perbaikannya?immutable
, dan saya akan takut orang menggunakan kembali objek pabrik karena mereka mengira begitu. Maksud saya: diFooFactory people = FooFactory.create().withType("person"); Foo women = people.withGender("female").build(); Foo talls = people.tallerThan("180m").build();
manatalls
sekarang hanya berisi wanita. Ini seharusnya tidak terjadi dengan API yang tidak dapat diubah.Di Scala 2.8, Anda dapat menggunakan parameter bernama dan default serta
copy
metode pada kelas kasus. Berikut beberapa contoh kode:sumber
Pertimbangkan ini di Scala 2.8:
Ini memang punya masalah, tentu saja. Misalnya, cobalah membuat
espouse
danOption[Person]
, lalu menikahi dua orang satu sama lain. Saya tidak dapat memikirkan cara untuk menyelesaikannya tanpa menggunakan salah satuprivate var
dan / atauprivate
konstruktor plus pabrik.sumber
Berikut ini beberapa opsi lainnya:
Pilihan 1
Jadikan implementasinya bisa berubah, tetapi pisahkan antarmuka yang diekspos menjadi bisa berubah dan tidak bisa diubah. Ini diambil dari desain perpustakaan Swing.
pilihan 2
Jika aplikasi Anda berisi kumpulan objek permanen yang besar tapi telah ditentukan sebelumnya (misalnya, objek konfigurasi), Anda dapat mempertimbangkan untuk menggunakan framework Spring .
sumber
Ini membantu untuk mengingat ada berbagai jenis kekekalan . Untuk kasus Anda, menurut saya keabadian "es loli" akan bekerja dengan sangat baik:
Jadi, Anda menginisialisasi objek Anda, lalu menyetel semacam tanda "beku" yang menunjukkan bahwa objek tersebut tidak lagi dapat ditulis. Lebih disukai, Anda menyembunyikan mutasi di balik suatu fungsi sehingga fungsi tersebut masih murni untuk klien yang menggunakan API Anda.
sumber
clone()
untuk mendapatkan contoh baru.freeze()
metode tersebut, semuanya bisa menjadi jelek.Anda juga dapat membuat objek yang tidak dapat diubah mengekspos metode yang terlihat seperti mutator (seperti addSibling) tetapi membiarkannya mengembalikan instance baru. Itulah yang dilakukan oleh koleksi Scala yang tidak dapat diubah.
Sisi negatifnya adalah Anda dapat membuat lebih banyak instance daripada yang diperlukan. Ini juga hanya berlaku jika ada konfigurasi valid perantara (seperti beberapa node tanpa saudara kandung yang ok dalam banyak kasus) kecuali Anda tidak ingin berurusan dengan objek yang dibangun sebagian.
Misalnya tepi grafik yang tidak memiliki tujuan belum merupakan tepi grafik yang valid.
sumber
Pertimbangkan empat kemungkinan:
Bagi saya, masing-masing 2, 3, dan 4 disesuaikan dengan situasi yang berbeda. Yang pertama sulit untuk dicintai, karena alasan yang dikutip oleh OP, dan umumnya merupakan gejala desain yang telah merayap dan perlu beberapa refactoring.
Apa yang saya cantumkan sebagai (2) adalah baik bila tidak ada keadaan di balik 'pabrik', sedangkan (3) adalah desain pilihan bila ada keadaan. Saya menemukan diri saya menggunakan (2) daripada (3) ketika saya tidak ingin khawatir tentang utas dan sinkronisasi, dan saya tidak perlu khawatir tentang amortisasi beberapa penyiapan yang mahal selama produksi banyak objek. (3), di sisi lain, dipanggil ketika pekerjaan nyata masuk ke dalam pembangunan pabrik (menyiapkan dari SPI, membaca file konfigurasi, dll).
Terakhir, jawaban orang lain menyebutkan opsi (4), di mana Anda memiliki banyak objek kecil yang tidak dapat diubah dan pola yang lebih disukai adalah mendapatkan berita dari yang lama.
Perhatikan bahwa saya bukan anggota 'klub penggemar pola' - tentu saja, beberapa hal patut ditiru, tetapi bagi saya tampaknya mereka menjalani kehidupan yang tidak membantu begitu orang memberi mereka nama dan topi lucu.
sumber
Opsi potensial lainnya adalah melakukan refaktorisasi agar memiliki lebih sedikit bidang yang dapat dikonfigurasi. Jika sekelompok bidang hanya bekerja (sebagian besar) satu sama lain, kumpulkan mereka ke dalam objek kecil mereka yang tidak dapat diubah. Konstruktor / pembangun objek "kecil" itu harus lebih mudah dikelola, seperti halnya konstruktor / pembangun untuk objek "besar" ini.
sumber
Saya menggunakan C #, dan ini adalah pendekatan saya. Mempertimbangkan:
Opsi 1. Pembuat dengan parameter opsional
Digunakan sebagai mis
new Foo(5, b: new Bar(whatever))
. Bukan untuk Java atau C # versi sebelum 4.0. tetapi tetap layak untuk ditampilkan, karena ini adalah contoh bagaimana tidak semua solusi bersifat tanpa bahasa.Opsi 2. Pembuat mengambil objek parameter tunggal
Contoh penggunaan:
C # dari 3.0 ke atas membuatnya lebih elegan dengan sintaks penginisialisasi objek (secara semantik setara dengan contoh sebelumnya):
Opsi 3:
Rancang ulang kelas Anda agar tidak membutuhkan banyak parameter. Anda dapat membagi tanggung jawabnya menjadi beberapa kelas. Atau berikan parameter bukan ke konstruktor tetapi hanya ke metode tertentu, sesuai permintaan. Tidak selalu dapat dijalankan, tetapi jika memungkinkan, itu layak dilakukan.
sumber