Saya menemukan bahwa konstruktor saya mulai terlihat seperti ini:
public MyClass(Container con, SomeClass1 obj1, SomeClass2, obj2.... )
dengan daftar parameter yang semakin meningkat. Karena "Kontainer" adalah wadah injeksi ketergantungan saya, mengapa saya tidak bisa melakukan ini saja:
public MyClass(Container con)
untuk setiap kelas? Apa kerugiannya? Jika saya melakukan ini, rasanya saya menggunakan statis yang dimuliakan. Silakan bagikan pemikiran Anda tentang kegilaan IoC dan Dependency Injection
c#
java
dependency-injection
inversion-of-control
ioc-container
JP Richardson
sumber
sumber
Jawaban:
Anda benar bahwa jika Anda menggunakan wadah sebagai Pencari Layanan, ini lebih atau kurang merupakan pabrik statis yang dimuliakan. Untuk banyak alasan saya menganggap ini sebagai anti-pola .
Salah satu manfaat luar biasa dari Injeksi Konstruktor adalah membuat pelanggaran terhadap Prinsip Tanggung Jawab Tunggal menjadi sangat jelas.
Ketika itu terjadi, saatnya untuk refactor ke Layanan Fasad . Singkatnya, buat antarmuka baru yang lebih berbutir kasar yang menyembunyikan interaksi antara beberapa atau semua dependensi berbutir halus yang saat ini Anda butuhkan.
sumber
Saya tidak berpikir konstruktor kelas Anda harus memiliki referensi ke periode kontainer IOC Anda. Ini mewakili ketergantungan yang tidak perlu antara kelas Anda dan wadah (jenis ketergantungan yang coba dihindari oleh IOC!).
sumber
MyClass myClass = new MyClass(IDependency1 interface1, IDependency2 interface2)
(parameter antarmuka). Ini tidak terkait dengan pos derivasi @, yang saya tafsirkan sebagai mengatakan wadah injeksi dependensi tidak boleh menyuntikkan dirinya ke objeknya, yaitu,MyClass myClass = new MyClass(this)
Kesulitan melewati parameter tidak menjadi masalah. Masalahnya adalah kelas Anda melakukan terlalu banyak, dan harus dipecah lagi.
Ketergantungan Injeksi dapat bertindak sebagai peringatan dini untuk kelas yang terlalu besar, khususnya karena meningkatnya rasa sakit lulus di semua dependensi.
sumber
Saya menemukan pertanyaan serupa tentang Injeksi ketergantungan berbasis konstruktor dan betapa rumitnya untuk melewati semua dependensi.
Salah satu pendekatan, saya telah digunakan di masa lalu adalah dengan menggunakan pola fasad aplikasi menggunakan lapisan layanan. Ini akan memiliki API kasar. Jika layanan ini tergantung pada repositori, Ini akan menggunakan injeksi setter dari properti pribadi. Ini membutuhkan pembuatan pabrik abstrak dan memindahkan logika menciptakan repositori ke pabrik.
Kode lengkap dengan penjelasan dapat ditemukan di sini
Praktik terbaik untuk IoC di lapisan layanan yang kompleks
sumber
Saya membaca seluruh utas ini, dua kali, dan saya pikir orang merespons dengan apa yang mereka ketahui, bukan dengan apa yang diminta.
Pertanyaan asli JP terlihat seperti dia membangun objek dengan mengirimkan resolver, dan kemudian banyak kelas, tapi kami mengasumsikan bahwa kelas / objek itu sendiri adalah layanan, siap untuk injeksi. Bagaimana jika tidak?
JP, jika Anda ingin memanfaatkan DI dan menginginkan kemuliaan pencampuran injeksi dengan data kontekstual, tidak satu pun dari pola-pola ini (atau yang diduga "anti-pola") yang secara khusus mengatasinya. Itu sebenarnya bermuara pada menggunakan paket yang akan mendukung Anda dalam upaya seperti itu.
... format ini jarang didukung. Saya percaya kesulitan pemrograman dukungan seperti itu, ditambahkan ke kinerja menyedihkan yang akan dikaitkan dengan implementasi, membuatnya tidak menarik bagi pengembang opensource.
Tapi itu harus dilakukan, karena saya harus dapat membuat dan mendaftarkan pabrik untuk MyClass'es, dan pabrik itu harus dapat menerima data / input yang tidak didorong menjadi "layanan" hanya demi melewati data. Jika "anti-pola" adalah tentang konsekuensi negatif, maka memaksakan keberadaan jenis layanan buatan untuk meneruskan data / model tentu negatif (setara dengan perasaan Anda tentang membungkus kelas Anda ke dalam wadah. Naluri yang sama berlaku).
Ada beberapa kerangka kerja yang mungkin membantu, meskipun mereka terlihat agak jelek. Misalnya, Ninject:
Membuat instance menggunakan Ninject dengan parameter tambahan di konstruktor
Itu untuk .NET, populer, dan masih tidak bersih seperti seharusnya, tapi saya yakin ada sesuatu dalam bahasa apa pun yang Anda pilih untuk digunakan.
sumber
Menyuntikkan wadah adalah jalan pintas yang akhirnya akan Anda sesali.
Injeksi yang berlebihan bukan masalahnya, biasanya merupakan gejala dari kelemahan struktural lainnya, terutama pemisahan kekhawatiran. Ini bukan satu masalah tetapi dapat memiliki banyak sumber dan apa yang membuat ini sangat sulit untuk diperbaiki adalah bahwa Anda harus berurusan dengan semuanya, kadang-kadang pada saat yang sama (pikirkan untuk melepaskan spageti).
Berikut adalah daftar hal-hal yang tidak perlu diwaspadai
Desain Domain Buruk (Agregat root .... dll.)
Pemisahan keprihatinan yang buruk (Komposisi layanan, Perintah, pertanyaan) Lihat CQRS dan Event Sourcing.
ATAU Pemetaan (hati-hati, hal-hal ini dapat membawa Anda ke masalah)
Lihat Model dan DTO lainnya (Jangan pernah gunakan kembali, dan cobalah untuk meminimalkannya !!!!)
sumber
Masalah:
1) Konstruktor dengan daftar parameter yang semakin meningkat.
2) Jika kelas diwariskan (Contoh:)
RepositoryBase
maka mengubah tanda tangan konstruktor menyebabkan perubahan dalam kelas turunan.Solusi 1
Lulus
IoC Container
ke konstruktorMengapa
Kenapa tidak
Solusi 2
Buat kelas yang mengelompokkan semua layanan dan meneruskannya ke konstruktor
Kelas turunan
Mengapa
A
bergantung, informasi itu diakumulasikanA.Dependency
Kenapa tidak
X.Dependency
secara terpisah)IoC Container
Solusi 2 hanyalah mentah, jika ada argumen yang kuat menentangnya, maka komentar deskriptif akan dihargai
sumber
Ini adalah pendekatan yang saya gunakan
Berikut ini adalah pendekatan kasar bagaimana melakukan injeksi dan menjalankan konstruktor setelah menyuntikkan nilai. Ini adalah program yang berfungsi penuh.
Saat ini saya sedang mengerjakan proyek hobi yang berfungsi seperti ini https://github.com/Jokine/ToolProject/tree/Core
sumber
Kerangka kerja injeksi ketergantungan apa yang Anda gunakan? Sudahkah Anda mencoba menggunakan injeksi berbasis setter saja?
Manfaat untuk injeksi berbasis konstruktor adalah terlihat alami untuk programmer Java yang tidak menggunakan kerangka kerja DI. Anda perlu 5 hal untuk menginisialisasi kelas maka Anda memiliki 5 argumen untuk konstruktor Anda. The downside adalah apa yang Anda perhatikan, itu menjadi sulit ketika Anda memiliki banyak ketergantungan.
Dengan Spring, Anda bisa meneruskan nilai yang diperlukan dengan setter dan Anda bisa menggunakan @required annotations untuk memastikan bahwa mereka disuntikkan. The downside adalah bahwa Anda perlu memindahkan kode inisialisasi dari konstruktor ke metode lain dan memiliki panggilan Spring yang setelah semua dependensi disuntikkan dengan menandainya dengan @PostConstruct. Saya tidak yakin tentang kerangka kerja lain tetapi saya menganggap mereka melakukan sesuatu yang serupa.
Kedua cara bekerja, ini masalah preferensi.
sumber