Saya tahu ini adalah debat panas dan opini cenderung berubah seiring waktu tentang praktik pendekatan terbaik.
Saya biasa menggunakan injeksi lapangan khusus untuk kelas saya, sampai saya mulai membaca di blog yang berbeda (mis: petrikainulainen dan schauderhaft dan fowler ) tentang manfaat injeksi konstruktor. Saya telah beralih metodologi saya untuk menggunakan injeksi konstruktor untuk dependensi yang diperlukan dan injeksi setter untuk dependensi opsional.
Namun, saya baru-baru ini terlibat dalam perdebatan dengan penulis JMockit - sebuah kerangka kerja yang mengejek - di mana ia melihat konstruktor & penyetel injeksi sebagai praktik yang buruk dan menunjukkan bahwa komunitas JEE setuju dengannya.
Di dunia sekarang ini, adakah cara yang lebih disukai untuk melakukan injeksi? Apakah injeksi Lapangan lebih disukai?
Setelah beralih ke injeksi konstruktor dari injeksi lapangan dalam beberapa tahun terakhir, saya merasa jauh lebih jelas untuk digunakan, tetapi saya bertanya-tanya apakah saya harus memeriksa kembali sudut pandang saya. Penulis JMockit (Rogério Liesenfeld) , jelas berpengalaman dalam DI, jadi saya merasa berkewajiban untuk meninjau pendekatan saya mengingat dia merasa sangat menentang konstruktor / penyetel injeksi.
sumber
Jawaban:
Injeksi lapangan agak terlalu "aksi seram di kejauhan" untuk seleraku.
Pertimbangkan contoh yang Anda berikan di pos Google Groups Anda:
Jadi pada dasarnya apa yang Anda katakan adalah bahwa "Saya memiliki kelas ini dengan negara pribadi, yang saya lampirkan
@injectable
penjelasan, yang berarti bahwa negara dapat secara otomatis diisi oleh beberapa agen dari luar, meskipun negara saya semuanya telah dinyatakan pribadi. "Saya mengerti motivasi untuk ini. Ini adalah upaya untuk menghindari banyak upacara yang melekat dalam mendirikan kelas dengan benar. Pada dasarnya, yang dikatakan orang adalah, "Aku bosan menulis semua pelat ini, jadi aku hanya akan membubuhi keterangan tentang negara bagianku, dan biarkan wadah DI mengurus pengaturannya untukku."
Ini sudut pandang yang benar-benar valid. Tapi itu juga solusi untuk fitur bahasa yang bisa dibilang tidak boleh dikerjakan. Juga, mengapa berhenti di situ? Secara tradisional, DI mengandalkan setiap kelas yang memiliki Interface pendamping. Mengapa tidak menghilangkan semua antarmuka itu dengan anotasi juga?
Pertimbangkan alternatifnya (ini akan menjadi C #, karena saya tahu lebih baik, tetapi mungkin ada padanan yang persis sama di Jawa):
Sudah saya tahu beberapa hal tentang kelas ini. Ini adalah kelas yang tidak berubah; negara hanya dapat diatur dalam konstruktor (referensi, dalam kasus khusus ini). Dan karena semuanya berasal dari sebuah antarmuka, saya bisa menukar implementasi di dalam konstruktor, yang merupakan tempat mengejek Anda.
Sekarang semua yang harus dilakukan wadah DI saya adalah merefleksikan konstruktor untuk menentukan objek apa yang diperlukan untuk memulai. Tapi refleksi itu dilakukan pada anggota publik, dengan cara kelas satu; yaitu metadata sudah menjadi bagian dari kelas, yang telah dinyatakan dalam konstruktor, sebuah metode yang tujuan ekspresinya adalah untuk menyediakan kelas dengan dependensi yang dibutuhkannya.
Memang ini banyak boilerplate, tetapi ini adalah bagaimana bahasa dirancang. Anotasi tampak seperti peretasan kotor untuk sesuatu yang seharusnya sudah ada dalam bahasa itu sendiri.
sumber
VeracodeService
hampir identik dengan yang Anda tulis (meskipun dalam Java vs C #). TheVeracodeServiceImplTest
sebenarnya kelas Unit Uji. Para@Injectable
bidang dasarnya mengejek benda yang dimasukkan ke dalam konteks. The@Tested
lapangan adalah objek / kelas dengan DI Constructor didefinisikan. Saya setuju dengan sudut pandang Anda yang lebih suka injeksi Konstruktor daripada injeksi lapangan. Namun, seperti yang saya sebutkan, penulis JMockit merasakan hal yang sebaliknya dan saya mencoba memahami mengapaArgumen kurang uji inisialisasi boiletplate valid, tetapi ada kekhawatiran lain yang harus diperhitungkan. Pertama-tama, Anda harus menjawab pertanyaan:
Apakah saya ingin kelas saya hanya instantiable dengan refleksi?
Menggunakan injeksi lapangan berarti mempersempit kompatibilitas kelas ke lingkungan injeksi ketergantungan yang membuat objek menggunakan refleksi dan mendukung anotasi injeksi khusus ini. Beberapa platform berbasis bahasa Java bahkan tidak mendukung refleksi ( GWT ), sehingga kelas yang diinjeksi lapangan tidak akan kompatibel dengan mereka.
Masalah kedua adalah kinerja . Panggilan konstruktor (langsung atau dengan refleksi) selalu lebih cepat daripada banyak tugas bidang refleksi. Kerangka kerja injeksi ketergantungan harus menggunakan analisis refleksi untuk membangun pohon dependensi dan membuat konstruktor refleksi. Proses ini menyebabkan hit kinerja tambahan.
Kinerja memengaruhi kemampuan pemeliharaan . Jika setiap rangkaian uji harus dijalankan dalam semacam wadah injeksi ketergantungan, serangkaian uji coba beberapa ribu unit dapat berlangsung puluhan menit. Bergantung pada ukuran basis kode, ini mungkin masalah.
Ini semua menimbulkan banyak pertanyaan baru:
Secara umum, semakin besar dan semakin penting suatu proyek, semakin signifikan faktor-faktor ini. Juga, Dari segi kualitas, kami umumnya ingin menjaga kode tinggi pada kompatibilitas, testability dan rawatan. Dari sudut pandang filosofis, injeksi lapangan memecah enkapsulasi , yang merupakan salah satu dari empat dasar pemrograman berorientasi objek , yang merupakan paradigma utama Jawa.
Banyak, banyak argumen menentang injeksi lapangan.
sumber
Injeksi lapangan mendapat suara "Tidak" yang pasti dari saya.
Seperti Robert Harvey, itu agak terlalu otomatis untuk seleraku. Saya lebih suka kode eksplisit daripada implisit, dan mentolerir tipuan hanya ketika memberikan manfaat yang jelas karena membuat kode lebih sulit untuk dipahami dan dipikirkan.
Seperti Maciej Chałapuk, saya tidak suka membutuhkan refleksi atau kerangka kerja DI / IoC untuk membuat instance kelas. Ini seperti mengemudi ke Roma untuk sampai ke Paris dari Amsterdam.
Pikiran Anda, saya suka DI dan semua keuntungan yang dibawanya. Hanya tidak yakin tentang membutuhkan kerangka kerja untuk membuat kelas. Terutama bukan efek bahwa wadah IoC atau kerangka kerja DI lainnya dapat memiliki pada kode uji.
Saya suka tes saya sangat mudah. Saya tidak suka harus melalui tipu daya menyiapkan wadah IOC atau kerangka kerja DI lainnya untuk kemudian membuat mereka mengatur kelas saya yang sedang diuji. Rasanya canggung.
Dan itu membuat tes saya tergantung pada keadaan global kerangka kerja. Artinya saya tidak bisa lagi menjalankan dua tes secara paralel yang membutuhkan instance kelas X untuk diatur dengan dependensi yang berbeda.
Setidaknya dengan konstruktor dan injeksi setter, Anda memiliki pilihan untuk tidak menggunakan kerangka kerja dan / atau refleksi dalam pengujian Anda.
sumber
Nah, ini sepertinya diskusi polemik. Hal pertama yang perlu diatasi adalah bahwa injeksi Field berbeda dari injeksi Setter . Saya sudah bekerja dengan beberapa orang yang berpikir injeksi Field dan Setter adalah hal yang sama.
Jadi, untuk menjadi jelas:
Injeksi lapangan:
Injeksi setter:
Tetapi, bagi saya, mereka memiliki keprihatinan yang sama. Dan, favorit saya, injeksi konstruktor:
Saya memiliki alasan berikut untuk meyakini bahwa injeksi konstruktor lebih baik daripada injeksi setter / bidang (saya akan mengutip beberapa tautan Spring untuk menunjukkan maksud saya):
@AutoWired
penyebaran yang lebih sedikit di antara kode Anda, kode Anda kurang tergantung pada kerangka kerja. Saya tahu bahwa kemungkinan untuk secara sederhana mengubah kerangka kerja DI dalam suatu proyek tidak membenarkan hal itu (siapa yang melakukan itu, bukan?). Tapi ini menunjukkan, bagi saya, kode yang lebih baik (saya belajar ini dengan cara yang sulit dengan EJB dan pencarian). Dan dengan Spring Anda bahkan dapat menghapus@AutoWired
anotasi menggunakan injeksi konstruktor.Jika Anda mencari informasi lebih lanjut, saya merekomendasikan artikel lama ini (tapi masih relevan) dari Spring Blog yang memberi tahu kami mengapa mereka menggunakan begitu banyak setter injeksi dan rekomendasi untuk menggunakan injeksi konstruktor:
Dan catatan ini tentang mengapa mereka percaya bahwa konstruktor lebih cocok untuk kode aplikasi:
Pikiran terakhir
Jika Anda tidak benar-benar yakin tentang keuntungan konstruktor, mungkin ide untuk mencampurkan setter (bukan bidang) dengan injeksi konstruktor adalah opsi, seperti yang dijelaskan oleh tim Spring :
Tapi ingat injeksi lapangan, mungkin, yang harus dihindari di antara ketiganya.
sumber
Apakah ketergantungan Anda cenderung berubah selama masa kelas? Jika demikian gunakan bidang / injeksi properti. Kalau tidak, gunakan injeksi konstruktor.
sumber