Saya refactoring kelas dan menambahkan ketergantungan baru ke sana. Kelas saat ini mengambil dependensi yang ada di konstruktor. Jadi untuk konsistensi, saya menambahkan parameter ke konstruktor.
Tentu saja, ada beberapa subclass plus bahkan lebih banyak untuk unit test, jadi sekarang saya memainkan permainan berkeliling mengubah semua konstruktor untuk mencocokkan, dan itu butuh waktu lama.
Itu membuat saya berpikir bahwa menggunakan properti dengan setter adalah cara yang lebih baik untuk mendapatkan dependensi. Saya tidak berpikir dependensi yang disuntikkan harus menjadi bagian dari antarmuka untuk membangun sebuah instance dari sebuah kelas. Anda menambahkan dependensi dan sekarang semua pengguna Anda (subclass dan siapa pun yang memberi Anda instantiasi secara langsung) tiba-tiba mengetahuinya. Rasanya seperti istirahat enkapsulasi.
Ini tampaknya bukan pola dengan kode yang ada di sini, jadi saya mencari tahu apa konsensus umum, pro dan kontra dari konstruktor versus properti. Apakah menggunakan setter properti lebih baik?
sumber
Para pengguna kelas seharusnya tahu tentang dependensi kelas yang diberikan. Jika saya memiliki kelas yang, misalnya, terhubung ke database, dan tidak menyediakan sarana untuk menyuntikkan ketergantungan lapisan persistensi, pengguna tidak akan pernah tahu bahwa koneksi ke database harus tersedia. Namun, jika saya mengubah konstruktor saya memberi tahu pengguna bahwa ada ketergantungan pada lapisan ketekunan.
Juga, untuk mencegah diri Anda harus mengubah setiap penggunaan konstruktor lama, cukup menerapkan chaining konstruktor sebagai jembatan sementara antara konstruktor lama dan baru.
Salah satu poin injeksi ketergantungan adalah untuk mengungkapkan dependensi apa yang dimiliki kelas. Jika kelas memiliki terlalu banyak dependensi, maka mungkin inilah saatnya refactoring dilakukan: Apakah setiap metode dalam kelas menggunakan semua dependensi? Jika tidak, maka itu adalah titik awal yang baik untuk melihat di mana kelas dapat dibagi.
sumber
Tentu saja, mengenakan konstruktor berarti Anda dapat memvalidasi sekaligus. Jika Anda menetapkan hal-hal ke dalam bidang read-only maka Anda memiliki beberapa jaminan tentang dependensi objek Anda sejak waktu konstruksi.
Ini adalah rasa sakit yang nyata menambahkan dependensi baru, tetapi setidaknya dengan cara ini kompiler terus mengeluh sampai benar. Itu hal yang baik, saya pikir.
sumber
Jika Anda memiliki banyak dependensi opsional (yang sudah tercium) maka mungkin injeksi setter adalah cara yang harus dilakukan. Injeksi konstruktor lebih baik mengungkapkan ketergantungan Anda.
sumber
Pendekatan umum yang disukai adalah menggunakan injeksi konstruktor sebanyak mungkin.
Injeksi konstruktor secara tepat menyatakan apa saja dependensi yang diperlukan agar objek berfungsi dengan benar - tidak ada yang lebih menjengkelkan daripada membuat objek baru dan membuatnya crash ketika memanggil metode di atasnya karena beberapa dependensi tidak diatur. Objek yang dikembalikan oleh konstruktor harus dalam kondisi aktif.
Cobalah untuk hanya memiliki satu konstruktor, itu membuat desain tetap sederhana dan menghindari ambiguitas (jika bukan untuk manusia, untuk wadah DI).
Anda dapat menggunakan injeksi properti ketika Anda memiliki apa yang oleh Mark Seemann disebut default lokal di bukunya "Dependency Injection in .NET": ketergantungan adalah opsional karena Anda dapat memberikan implementasi yang berfungsi baik tetapi ingin mengizinkan penelepon menentukan yang berbeda jika dibutuhkan.
(Mantan jawaban di bawah)
Saya pikir injeksi konstruktor lebih baik jika injeksi wajib. Jika ini menambahkan terlalu banyak konstruktor, pertimbangkan untuk menggunakan pabrik dan bukan konstruktor.
Injeksi setter baik jika injeksi opsional, atau jika Anda ingin mengubahnya setengah jalan. Saya biasanya tidak suka setter, tapi ini masalah selera.
sumber
Ini sebagian besar masalah selera pribadi. Secara pribadi saya cenderung lebih suka injeksi penyetel, karena saya percaya itu memberi Anda lebih banyak fleksibilitas dalam cara yang Anda bisa mengganti implementasi saat runtime. Selain itu, konstruktor dengan banyak argumen tidak bersih menurut pendapat saya, dan argumen yang disediakan dalam konstruktor harus dibatasi pada argumen non-opsional.
Selama antarmuka kelas (API) jelas dalam apa yang diperlukan untuk melakukan tugasnya, Anda baik.
sumber
Saya pribadi lebih suka "pola" Ekstrak dan Timpa daripada menyuntikkan dependensi dalam konstruktor, sebagian besar karena alasan yang diuraikan dalam pertanyaan Anda. Anda bisa mengatur properti sebagai
virtual
dan kemudian menimpa implementasi di kelas yang dapat diuji yang diturunkan.sumber
Saya lebih suka injeksi konstruktor karena ini membantu "menegakkan" persyaratan ketergantungan kelas. Jika ada dalam c'tor, konsumen harus mengatur objek untuk mendapatkan kompilasi aplikasi. Jika Anda menggunakan suntikan setter, mereka mungkin tidak tahu bahwa mereka memiliki masalah sampai waktu berjalan - dan tergantung pada objeknya, itu mungkin terlambat dalam waktu berjalan.
Saya masih menggunakan injeksi setter dari waktu ke waktu ketika objek yang diinjeksi mungkin membutuhkan banyak pekerjaan itu sendiri, seperti inisialisasi.
sumber
Saya menolak injeksi konstruktor, karena ini tampaknya paling logis. Seperti mengatakan kelas saya membutuhkan dependensi ini untuk melakukan tugasnya. Jika ini merupakan ketergantungan opsional maka properti tampak masuk akal.
Saya juga menggunakan injeksi properti untuk mengatur hal-hal yang tidak memiliki referensi ke wadah seperti ASP.NET View pada presenter yang dibuat menggunakan wadah.
Saya tidak berpikir itu merusak enkapsulasi. Pekerjaan batin harus tetap internal dan ketergantungan menangani masalah yang berbeda.
sumber
Salah satu opsi yang mungkin layak dipertimbangkan adalah menyusun multi-dependensi kompleks dari dependensi tunggal sederhana. Artinya, tentukan kelas tambahan untuk dependensi majemuk. Ini membuat segalanya sedikit lebih mudah injeksi konstruktor WRT - lebih sedikit parameter per panggilan - sambil tetap mempertahankan hal-hal yang harus disediakan-semua-dependensi-untuk-instantiate.
Tentu saja sangat masuk akal jika ada semacam pengelompokan dependensi logis, sehingga senyawa lebih dari agregat sewenang-wenang, dan masuk akal jika ada banyak tanggungan untuk dependensi senyawa tunggal - tetapi "parameter" blok parameter memiliki sudah ada sejak lama, dan sebagian besar yang saya lihat cukup sewenang-wenang.
Namun secara pribadi, saya lebih suka menggunakan metode / properti-setter untuk menentukan dependensi, opsi dll. Nama panggilan membantu menjelaskan apa yang sedang terjadi. Adalah ide yang baik untuk memberikan contoh snippet ini-bagaimana-untuk-mengatur-itu, dan pastikan kelas dependen melakukan cukup pengecekan kesalahan. Anda mungkin ingin menggunakan model kondisi hingga untuk pengaturan.
sumber
Saya baru-baru ini mengalami situasi di mana saya memiliki banyak dependensi di kelas, tetapi hanya satu dependensi yang akan berubah dalam setiap implementasi. Karena akses data dan dependensi logging kesalahan kemungkinan hanya akan diubah untuk tujuan pengujian, saya menambahkan parameter opsional untuk dependensi tersebut dan memberikan implementasi default dari dependensi tersebut dalam kode konstruktor saya. Dengan cara ini, kelas mempertahankan perilaku defaultnya kecuali dikesampingkan oleh konsumen kelas.
Menggunakan parameter opsional hanya dapat dicapai dalam kerangka kerja yang mendukungnya, seperti .NET 4 (untuk C # dan VB.NET, meskipun VB.NET selalu memilikinya). Tentu saja, Anda dapat mencapai fungsi serupa dengan hanya menggunakan properti yang dapat dipindahkan oleh konsumen kelas Anda, tetapi Anda tidak mendapatkan keuntungan dari ketidakberdayaan yang disediakan dengan memiliki objek antarmuka pribadi yang ditugaskan ke parameter konstruktor.
Semua ini dikatakan, jika Anda memperkenalkan ketergantungan baru yang harus disediakan oleh setiap konsumen, Anda harus memperbaiki konstruktor Anda dan semua kode yang konsumen kelas Anda. Saran saya di atas benar-benar hanya berlaku jika Anda memiliki kemewahan untuk dapat memberikan implementasi default untuk semua kode Anda saat ini tetapi masih memberikan kemampuan untuk menimpa implementasi default jika perlu.
sumber
Ini adalah pos lama, tetapi jika diperlukan di masa depan mungkin ini ada gunanya:
https://github.com/omegamit6zeichen/prinject
Saya punya ide yang sama dan muncul dengan kerangka kerja ini. Ini mungkin jauh dari lengkap, tetapi ini adalah gagasan tentang kerangka kerja yang berfokus pada injeksi properti
sumber
Itu tergantung pada bagaimana Anda ingin menerapkan. Saya lebih suka injeksi konstruktor di mana pun saya merasakan nilai-nilai yang masuk ke implementasi tidak sering berubah. Misalnya: Jika perusahaan compnay pergi dengan server oracle, saya akan mengkonfigurasi nilai datsource saya untuk koneksi yang mencapai kacang melalui injeksi konstruktor. Selain itu, jika aplikasi saya adalah produk dan kemungkinan dapat terhubung ke db pelanggan, saya akan menerapkan konfigurasi db dan implementasi multi-merek melalui injeksi setter. Saya baru saja mengambil contoh tetapi ada cara yang lebih baik untuk mengimplementasikan skenario yang saya sebutkan di atas.
sumber
Injeksi konstruktor secara eksplisit mengungkapkan dependensi, membuat kode lebih mudah dibaca dan lebih rentan terhadap kesalahan run-time yang tidak ditangani jika argumen diperiksa dalam konstruktor, tetapi itu benar-benar turun ke pendapat pribadi, dan semakin Anda menggunakan DI semakin Anda akan semakin cenderung bergoyang-goyang satu dan lain cara tergantung pada proyek. Saya pribadi memiliki masalah dengan bau kode seperti konstruktor dengan daftar panjang argumen, dan saya merasa bahwa konsumen suatu objek harus mengetahui dependensi untuk menggunakan objek, jadi ini membuat kasus untuk menggunakan injeksi properti. Saya tidak suka sifat implisit dari injeksi properti, tetapi saya merasa lebih elegan, menghasilkan kode yang tampak lebih bersih. Tetapi di sisi lain, injeksi konstruktor memang menawarkan tingkat enkapsulasi yang lebih tinggi,
Pilih injeksi dengan konstruktor atau berdasarkan properti dengan bijak berdasarkan skenario spesifik Anda. Dan jangan merasa bahwa Anda harus menggunakan DI hanya karena tampaknya perlu dan itu akan mencegah desain dan bau kode yang buruk. Terkadang tidak sepadan dengan upaya untuk menggunakan suatu pola jika upaya dan kompleksitasnya melebihi manfaatnya. Tetap sederhana.
sumber