Kapan tidak tepat menggunakan pola injeksi ketergantungan?

124

Sejak belajar (dan mencintai) pengujian otomatis saya menemukan diri saya menggunakan pola injeksi ketergantungan di hampir setiap proyek. Apakah selalu tepat untuk menggunakan pola ini ketika bekerja dengan pengujian otomatis? Apakah ada situasi yang harus Anda hindari menggunakan injeksi ketergantungan?

Tom Squires
sumber
1
Terkait (mungkin bukan duplikat) - stackoverflow.com/questions/2407540/…
Steve314
3
Kedengarannya agak seperti anti-pola Palu Emas. en.wikipedia.org/wiki/Anti-pattern
Cuga

Jawaban:

123

Pada dasarnya, injeksi ketergantungan membuat beberapa (biasanya tetapi tidak selalu valid) asumsi tentang sifat objek Anda. Jika itu salah, DI mungkin bukan solusi terbaik:

  • Pertama, pada dasarnya, DI mengasumsikan bahwa kopling ketat dari implementasi objek SELALU buruk . Ini adalah inti dari Prinsip Ketergantungan Pembalikan: "ketergantungan tidak boleh dibuat pada konkret; hanya pada abstraksi".

    Ini menutup objek dependen untuk berubah berdasarkan perubahan pada implementasi konkret; sebuah kelas tergantung pada ConsoleWriter secara khusus akan perlu berubah jika output perlu pergi ke file sebagai gantinya, tetapi jika kelas hanya bergantung pada IWriter yang mengekspos metode Write (), kita dapat mengganti ConsoleWriter yang saat ini digunakan dengan FileWriter dan kelas dependen tidak akan tahu bedanya (Prinsip Pergantian Liskhov).

    Namun, suatu desain TIDAK PERNAH bisa ditutup untuk semua jenis perubahan; jika desain antarmuka IWriter itu sendiri berubah, untuk menambahkan parameter ke Write (), objek kode tambahan (antarmuka IWriter) sekarang harus diubah, di atas objek / metode implementasi dan penggunaannya. Jika perubahan dalam antarmuka yang sebenarnya lebih mungkin daripada perubahan pada implementasi antarmuka tersebut, kopling longgar (dan ketergantungan DI-ing longgar-digabungkan) dapat menyebabkan lebih banyak masalah daripada memecahkannya.

  • Kedua, dan wajar, DI mengasumsikan bahwa kelas dependen TIDAK PERNAH merupakan tempat yang baik untuk menciptakan ketergantungan . Ini berlaku untuk Prinsip Tanggung Jawab Tunggal; jika Anda memiliki kode yang menciptakan dependensi dan juga menggunakannya, maka ada dua alasan kelas dependen mungkin harus berubah (perubahan penggunaan ATAU implementasi), melanggar SRP.

    Namun, sekali lagi, menambahkan lapisan tipuan untuk DI dapat menjadi solusi untuk masalah yang tidak ada; jika logis untuk merangkum logika dalam dependensi, tetapi logika itu adalah satu-satunya implementasi dari dependensi, maka lebih menyakitkan untuk mengkodekan resolusi dependensi yang digabungkan secara longgar (injeksi, lokasi layanan, pabrik) daripada yang seharusnya. hanya menggunakan newdan melupakannya.

  • Terakhir, DI pada dasarnya memusatkan pengetahuan tentang semua dependensi DAN implementasinya . Ini meningkatkan jumlah referensi yang harus dimiliki oleh majelis yang melakukan injeksi, dan dalam kebanyakan kasus TIDAK mengurangi jumlah referensi yang diperlukan oleh majelis kelas dependen yang sebenarnya.

    SESUATU, DI TEMPAT LAIN, harus memiliki pengetahuan tentang ketergantungan, antarmuka ketergantungan, dan implementasi ketergantungan untuk "menghubungkan titik-titik" dan memenuhi ketergantungan itu. DI cenderung menempatkan semua pengetahuan itu pada tingkat yang sangat tinggi, baik dalam wadah IoC, atau dalam kode yang menciptakan objek "utama" seperti bentuk utama atau Pengendali yang harus menghidrasi (atau menyediakan metode pabrik untuk) dependensi. Ini dapat menempatkan banyak kode yang harus dipasangkan dengan ketat dan banyak referensi perakitan di tingkat tinggi aplikasi Anda, yang hanya membutuhkan pengetahuan ini untuk "menyembunyikan" dari kelas dependen yang sebenarnya (yang dari perspektif yang sangat mendasar adalah tempat terbaik untuk memiliki pengetahuan ini; di mana itu digunakan).

    Itu juga biasanya tidak menghapus referensi kata dari bawah kode; dependen masih harus merujuk pustaka yang berisi antarmuka untuk ketergantungannya, yang ada di salah satu dari tiga tempat:

    • semua dalam satu perakitan "Antarmuka" yang menjadi sangat aplikasi-sentris,
    • masing-masing di samping implementasi utama, menghilangkan keuntungan dari tidak harus mengkompilasi ulang tanggungan ketika dependensi berubah, atau
    • satu atau dua masing-masing dalam rakitan yang sangat kohesif, yang menggembungkan jumlah rakitan, secara dramatis meningkatkan waktu "pembangunan penuh" dan menurunkan kinerja aplikasi.

    Semua ini, sekali lagi untuk menyelesaikan masalah di tempat-tempat di mana mungkin tidak ada.

KeithS
sumber
1
SRP = prinsip tanggung jawab tunggal, untuk orang lain yang bertanya-tanya.
Theodore Murdock
1
Ya, dan LSP adalah prinsip Substitusi Liskov; diberi ketergantungan pada A, ketergantungan tersebut harus dapat dipenuhi oleh B yang berasal dari A tanpa ada perubahan lain.
KeithS
injeksi dependensi secara khusus membantu di mana Anda perlu mendapatkan kelas A dari kelas B dari kelas D dll. dalam kasus itu (dan hanya itu kasus) kerangka kerja DI dapat menghasilkan mengasapi perakitan lebih sedikit daripada injeksi orang miskin. juga saya tidak pernah mengalami hambatan yang disebabkan oleh DI .. berpikir untuk biaya pemeliharaan, tidak pernah untuk biaya cpu karena kode selalu dapat dioptimalkan, tetapi melakukan itu tanpa alasan memiliki biaya
GameDeveloper
Apakah asumsi lain adalah "jika perubahan berubah itu berubah di mana-mana"? Atau Anda harus melihat semua kelas konsumsi
Richard Tingle
3
Jawaban ini gagal untuk mengatasi dampak testability dari ketergantungan injeksi versus hardcoding mereka. Lihat juga Prinsip Ketergantungan Eksplisit ( deviq.com/explicit-dependencies-principle )
ssmith
30

Di luar kerangka kerja dependensi-injeksi, injeksi dependensi (melalui injeksi konstruktor atau injeksi setter) hampir merupakan permainan zero-sum: Anda mengurangi sambungan antara objek A dan dependensi B itu, tetapi sekarang semua objek yang membutuhkan instance A sekarang harus juga membangun objek B.

Anda telah sedikit mengurangi kopling antara A dan B, tetapi mengurangi enkapsulasi A, dan meningkatkan kopling antara A dan setiap kelas yang harus membuat turunan A, dengan menyambungkannya ke dependensi A juga.

Jadi injeksi ketergantungan (tanpa kerangka kerja) adalah sama-sama berbahaya karena sangat membantu.

Biaya tambahan seringkali mudah dibenarkan, namun: jika kode klien lebih tahu tentang bagaimana membangun ketergantungan daripada objek itu sendiri, maka injeksi ketergantungan benar-benar mengurangi kopling; misalnya, Pemindai tidak tahu banyak tentang cara mendapatkan atau membangun aliran input untuk mem-parsing input, atau sumber dari mana kode klien ingin mem-parsing input, jadi injeksi konstruktor dari aliran input adalah solusi yang jelas.

Pengujian adalah pembenaran lain, agar dapat menggunakan dependensi tiruan. Itu harus berarti menambahkan konstruktor tambahan yang digunakan hanya untuk pengujian yang memungkinkan dependensi disuntikkan: jika Anda mengganti konstruktor Anda untuk selalu memerlukan dependensi yang akan disuntikkan, tiba-tiba, Anda harus tahu tentang dependensi dependensi Anda untuk membangun Anda ketergantungan langsung, dan Anda tidak dapat menyelesaikan pekerjaan.

Ini bisa membantu, tetapi Anda harus bertanya pada diri sendiri untuk setiap ketergantungan, apakah manfaat pengujian sebanding dengan biayanya, dan apakah saya benar-benar ingin mengejek ketergantungan ini saat pengujian?

Ketika kerangka kerja dependensi-injeksi ditambahkan, dan konstruksi dependensi didelegasikan bukan ke kode klien tetapi sebaliknya ke kerangka kerja, analisis biaya / manfaat sangat berubah.

Dalam kerangka kerja ketergantungan-injeksi, pengorbanannya sedikit berbeda; apa yang Anda kehilangan dengan menyuntikkan dependensi adalah kemampuan untuk mengetahui dengan mudah implementasi apa yang Anda andalkan, dan mengalihkan tanggung jawab untuk memutuskan dependensi apa yang Anda andalkan untuk beberapa proses resolusi otomatis (misalnya jika kami memerlukan @ Inject'ed Foo , harus ada sesuatu yang menyediakan @Foo, dan yang dependensinya disuntikkan tersedia), atau ke beberapa file konfigurasi tingkat tinggi yang menentukan penyedia apa yang harus digunakan untuk setiap sumber daya, atau untuk beberapa hibrida dari keduanya (misalnya, mungkin ada menjadi proses resolusi otomatis untuk dependensi yang dapat diganti, jika perlu, menggunakan file konfigurasi).

Seperti dalam injeksi konstruktor, saya pikir keuntungan dari melakukannya berakhir, sekali lagi, sangat mirip dengan biaya melakukannya: Anda tidak perlu tahu siapa yang menyediakan data yang Anda andalkan, dan, jika ada banyak potensi penyedia, Anda tidak perlu tahu urutan pilihan untuk memeriksa penyedia di, pastikan bahwa setiap lokasi yang membutuhkan data memeriksa semua penyedia potensial, dll., karena semua itu ditangani pada tingkat tinggi oleh injeksi ketergantungan peron.

Meskipun saya secara pribadi tidak memiliki banyak pengalaman dengan kerangka kerja DI, kesan saya adalah mereka memberikan lebih banyak manfaat daripada biaya ketika sakit kepala menemukan penyedia data atau layanan yang Anda butuhkan memiliki biaya lebih tinggi daripada sakit kepala, ketika sesuatu gagal, tidak segera mengetahui secara lokal kode apa yang menyediakan data buruk yang kemudian menyebabkan kegagalan pada kode Anda.

Dalam beberapa kasus, pola-pola lain yang mengaburkan ketergantungan (misalnya pencari layanan) telah diadopsi (dan mungkin juga terbukti nilainya) ketika kerangka kerja DI muncul di tempat kejadian, dan kerangka kerja DI diadopsi karena mereka menawarkan beberapa keunggulan kompetitif, seperti membutuhkan kode kurang boilerplate, atau berpotensi melakukan lebih sedikit untuk mengaburkan penyedia ketergantungan ketika menjadi perlu untuk menentukan penyedia apa yang sebenarnya digunakan.

Theodore Murdock
sumber
6
Hanya komentar singkat tentang dependensi mengejek dalam tes dan "Anda harus tahu tentang dependensi dependensi 'dependensi Anda" ... Itu tidak benar sama sekali. Seseorang tidak perlu tahu atau peduli tentang ketergantungan implementasi konkret jika tiruan sedang disuntikkan. Satu hanya perlu tahu tentang dependensi langsung dari kelas yang diuji, yang dipenuhi oleh mock (s).
Eric King
6
Anda salah paham, saya tidak berbicara tentang ketika Anda menyuntikkan mock, saya berbicara tentang kode asli. Pertimbangkan kelas A dengan dependensi B, yang pada gilirannya memiliki ketergantungan C, yang pada gilirannya memiliki ketergantungan D. Tanpa DI, A membangun B, B membangun C, C membangun D. Dengan injeksi konstruksi, untuk membangun A, Anda harus terlebih dahulu membangun B, untuk membangun B Anda pertama-tama harus membangun C, dan untuk membangun C Anda pertama-tama harus membangun D. Jadi kelas A sekarang harus tahu tentang D, ketergantungan dari ketergantungan dari suatu ketergantungan, untuk membangun B ini mengarah ke kopling yang berlebihan.
Theodore Murdock
1
Tidak akan ada begitu banyak biaya untuk memiliki konstruktor tambahan yang digunakan hanya untuk pengujian yang memungkinkan dependensi untuk disuntikkan. Saya akan mencoba merevisi apa yang saya katakan.
Theodore Murdock
3
Dosis injeksi ketergantungan hanya memindahkan ketergantungan dalam permainan zero sum. Anda memindahkan dependencirs Anda ke tempat-tempat yang sudah ada: proyek utama. Anda bahkan dapat menggunakan pendekatan berbasis konvensi untuk memastikan dependensi hanya diselesaikan pada saat run time, misalnya dengan menentukan kelas mana yang konkret berdasarkan ruang nama atau apa pun. Saya harus mengatakan ini adalah jawaban yang naif
Sprague
2
@Sprague Dependency injection bergerak di sekitar dependensi dalam permainan jumlah sedikit negatif, jika Anda menerapkannya dalam kasus di mana seharusnya tidak diterapkan. Tujuan dari jawaban ini adalah untuk mengingatkan orang bahwa injeksi ketergantungan tidak baik secara inheren, itu adalah pola desain yang sangat berguna dalam keadaan yang tepat, tetapi biaya yang tidak dapat dibenarkan dalam keadaan normal (setidaknya dalam domain pemrograman tempat saya pernah bekerja , Saya mengerti dalam beberapa domain ini lebih sering bermanfaat daripada yang lain). DI kadang-kadang menjadi kata kunci dan tujuan itu sendiri, yang melenceng.
Theodore Murdock
11
  1. jika Anda membuat entitas basis data, Anda lebih baik memiliki beberapa kelas pabrik yang Anda akan menyuntikkan ke controller Anda,

  2. jika Anda perlu membuat objek primitif seperti int atau panjang. Anda juga harus membuat "dengan tangan" sebagian besar objek perpustakaan standar seperti tanggal, panduan, dll.

  3. jika Anda ingin menyuntikkan string konfigurasi, mungkin ide yang lebih baik untuk menyuntikkan beberapa objek konfigurasi (secara umum disarankan untuk membungkus tipe sederhana menjadi objek yang bermakna: int temperatureInCelsiusDegrees -> CelciusDeegree temperature)

Dan jangan gunakan Service locator sebagai alternatif injeksi ketergantungan, ini anti-pola, info lebih lanjut: http://blog.ploeh.dk/2010/02/03/ServiceLocatorIsAnAntitiPattern.aspx

0lukasz0
sumber
Semua poinnya adalah tentang menggunakan berbagai bentuk injeksi daripada tidak menggunakannya sama sekali. +1 untuk tautan.
Jan Hudec
3
Service Locator BUKAN anti-pola dan orang yang Anda tautkan dengan blog bukan pakar pola. Yang ia dapatkan dari StackExchange-terkenal adalah semacam kerugian bagi desain perangkat lunak. Martin Fowler (penulis Pola pokok Arsitektur Aplikasi Perusahaan) memiliki pandangan yang lebih masuk akal mengenai masalah ini: martinfowler.com/articles/injection.html
Colin
1
@Colin, sebaliknya, Service Locator pasti merupakan anti-pola, dan di sini singkatnya adalah alasan mengapa .
Kyralessa
@ Kirralessa - Anda menyadari bahwa kerangka kerja DI secara internal menggunakan pola Layanan Locator untuk mencari layanan, kan? Ada situasi di mana keduanya sesuai, dan tidak ada yang anti pola meskipun StackExchange benci beberapa orang ingin membuang.
Colin
Tentu, dan mobil saya secara internal menggunakan piston dan busi dan sejumlah hal lain yang bukan, antarmuka yang bagus untuk manusia biasa yang hanya ingin mengendarai mobil.
Kyralessa
8

Ketika Anda tidak tahan untuk mendapatkan apa pun dengan membuat proyek Anda dapat dipelihara dan diuji.

Serius, saya suka IoC dan DI secara umum, dan saya akan mengatakan bahwa 98% dari waktu saya akan menggunakan pola itu tanpa gagal. Ini sangat penting dalam lingkungan multi-pengguna, di mana kode Anda dapat digunakan kembali berulang kali oleh anggota tim yang berbeda dan proyek yang berbeda, karena memisahkan logika dari implementasi. Pencatatan adalah contoh utama dari hal ini, antarmuka ILog yang disuntikkan ke dalam kelas seribu kali lebih mudah dikelola daripada hanya dengan memasukkan kerangka kerja logging Anda-du-jour, karena Anda tidak memiliki jaminan proyek lain akan menggunakan kerangka kerja logging yang sama (jika menggunakan satu sama sekali!).

Namun, ada kalanya itu bukan pola yang berlaku. Misalnya, titik masuk fungsional yang diimplementasikan dalam konteks statis oleh penginisialisasi yang tidak dapat ditimpa (WebMethods, saya sedang melihat Anda, tetapi metode Main () Anda di kelas Program adalah contoh lain) tidak bisa hanya memiliki ketergantungan yang disuntikkan pada inisialisasi. waktu. Saya juga mengatakan bahwa prototipe, atau potongan kode investigasi yang dibuang, juga merupakan kandidat yang buruk; manfaat DI adalah manfaat jangka menengah-panjang (testability dan rawatan) yang cukup banyak, jika Anda yakin akan membuang sebagian besar kode dalam waktu seminggu atau lebih, saya akan mengatakan Anda tidak mendapatkan apa-apa dengan mengisolasi dependensi, cukup habiskan waktu yang biasanya Anda habiskan untuk menguji dan mengisolasi dependensi agar kode berfungsi.

Secara keseluruhan, masuk akal untuk mengambil pendekatan pragmatis untuk setiap metodologi atau pola, karena tidak ada yang berlaku 100% dari waktu.

Satu hal yang perlu diperhatikan adalah komentar Anda tentang pengujian otomatis: definisi saya tentang ini adalah tes fungsional otomatis , misalnya tes selenium tertulis jika Anda berada dalam konteks web. Ini umumnya adalah tes kotak hitam sepenuhnya, tanpa perlu tahu tentang cara kerja kode. Jika Anda merujuk pada tes Unit atau Integrasi, saya akan mengatakan bahwa pola DI hampir selalu berlaku untuk proyek apa pun yang sangat bergantung pada jenis pengujian kotak putih, karena, misalnya, memungkinkan Anda untuk menguji hal-hal seperti metode yang menyentuh DB tanpa perlu hadir DB.

Ed James
sumber
Saya tidak mengerti maksud Anda tentang pencatatan. Tentunya semua penebang tidak akan sesuai dengan antarmuka yang sama sehingga Anda harus menulis pembungkus Anda sendiri untuk menerjemahkan antara cara logging proyek ini dan logger tertentu (dengan asumsi Anda ingin dapat dengan mudah mengubah penebang). Jadi setelah itu apa yang saya berikan kepada Anda?
Richard Tingle
@RichardTingle Saya akan mengatakan bahwa Anda harus mendefinisikan wrapper logging Anda sebagai antarmuka, dan kemudian Anda menulis implementasi antarmuka yang ringan untuk setiap layanan logging eksternal, daripada menggunakan kelas logging tunggal yang membungkus beberapa abstraksi. Ini adalah konsep yang sama yang Anda usulkan tetapi diabstraksi pada tingkat yang berbeda.
Ed James
1

Sementara jawaban lain fokus pada aspek teknis saya ingin menambahkan dimensi praktis.

Selama bertahun-tahun saya sampai pada kesimpulan bahwa ada beberapa persyaratan praktis yang harus dipenuhi jika memperkenalkan Injeksi Ketergantungan adalah untuk menjadi sukses.

  1. Seharusnya ada alasan untuk memperkenalkannya.

    Ini kedengarannya jelas, tetapi jika kode Anda hanya mendapatkan hal-hal dari database dan mengembalikannya tanpa logika apa pun, kemudian menambahkan sebuah wadah DI membuat segalanya menjadi lebih kompleks tanpa manfaat nyata. Pengujian integrasi akan lebih penting di sini.

  2. Tim perlu dilatih dan di atas kapal.

    Kecuali jika sebagian besar tim ada di papan dan memahami DI menambahkan inversi wadah kontrol menjadi cara lain untuk melakukan sesuatu dan membuat basis kode semakin rumit.

    Jika DI diperkenalkan oleh anggota baru tim, karena mereka memahaminya dan menyukainya dan hanya ingin menunjukkan bahwa mereka baik, DAN tim tidak terlibat aktif, ada risiko nyata bahwa DI itu akan benar-benar menurunkan kualitas Kode.

  3. Anda perlu menguji

    Sementara decoupling secara umum adalah hal yang baik, DI dapat memindahkan resolusi ketergantungan dari waktu kompilasi ke waktu berjalan. Ini sebenarnya cukup berbahaya jika Anda tidak menguji dengan baik. Jalankan kegagalan resolusi waktu dapat mahal untuk dilacak dan diselesaikan.
    (Jelas dari tes Anda bahwa Anda melakukannya, tetapi banyak tim tidak menguji sejauh yang disyaratkan oleh DI.)

tymtam
sumber
1

Ini bukan jawaban yang lengkap, tetapi hanya poin lain.

Ketika Anda memiliki aplikasi yang mulai sekali, berjalan untuk waktu yang lama (seperti aplikasi web) DI mungkin baik.

Ketika Anda memiliki aplikasi yang mulai berkali-kali dan berjalan untuk waktu yang lebih singkat (seperti aplikasi seluler), Anda mungkin tidak menginginkan wadah.

Koray Tugay
sumber
Saya tidak melihat bagaimana waktu aplikasi yang terkait dengan DI
Michael Freidgeim
@MichaelFreidgeim Butuh waktu untuk menginisialisasi konteksnya, biasanya wadah DI cukup berat, seperti Spring. Buat aplikasi hello world dengan hanya satu kelas dan buat satu dengan Spring dan mulai keduanya 10 kali dan Anda akan melihat apa yang saya maksud.
Koray Tugay
Kedengarannya seperti masalah dengan wadah DI individu. Di dunia .Net saya belum pernah mendengar tentang waktu inisialisasi sebagai masalah penting untuk wadah DI
Michael Freidgeim
1

Cobalah untuk menggunakan prinsip-prinsip OOP dasar: gunakan pewarisan untuk mengekstrak fungsionalitas umum, merangkum (menyembunyikan) hal-hal, yang harus dilindungi dari dunia luar menggunakan anggota / tipe pribadi / internal / terlindungi. Gunakan kerangka uji yang kuat untuk menyuntikkan kode hanya untuk tes, misalnya https://www.typemock.com/ atau https://www.telerik.com/products/mocking.aspx .

Kemudian cobalah menulis ulang dengan DI, dan bandingkan kode, yang biasanya Anda lihat dengan DI:

  1. Anda memiliki lebih banyak antarmuka (lebih banyak tipe)
  2. Anda telah membuat duplikat tanda tangan dari metode publik dan Anda harus menggandakannya (Anda tidak bisa begitu saja mengubah beberapa parameter sekali saja, Anda harus melakukannya dua kali, pada dasarnya semua kemungkinan refactoring dan navigasi menjadi lebih rumit)
  3. Anda telah memindahkan beberapa kesalahan kompilasi untuk menjalankan kegagalan waktu (dengan DI Anda dapat mengabaikan beberapa dependensi selama pengkodean dan tidak yakin itu akan diekspos selama pengujian)
  4. Anda telah membuka enkapsulasi Anda. Sekarang anggota yang dilindungi, tipe internal dll menjadi publik
  5. Jumlah keseluruhan kode meningkat

Saya akan mengatakan dari apa yang saya lihat, hampir selalu, kualitas kode sedang menurun dengan DI.

Namun, jika Anda hanya menggunakan pengubah akses "publik" dalam deklarasi kelas, dan / atau pengubah publik / pribadi untuk anggota, dan / atau Anda tidak memiliki pilihan untuk membeli alat uji mahal dan pada saat yang sama Anda memerlukan pengujian unit yang dapat ' t digantikan oleh pengujian integrasional, dan / atau Anda sudah memiliki antarmuka untuk kelas yang Anda pikir untuk menyuntikkan, DI adalah pilihan yang baik!

ps mungkin saya akan mendapatkan banyak minus untuk posting ini, saya percaya karena sebagian besar pengembang modern tidak mengerti bagaimana dan mengapa menggunakan kata kunci internal dan bagaimana mengurangi kopling komponen Anda dan akhirnya mengapa untuk menguranginya) akhirnya, hanya coba kode dan bandingkan

Eugene Gorbovoy
sumber
0

Sebuah alternatif untuk Dependency Injection menggunakan Layanan Locator . Service Locator lebih mudah dipahami, didebug, dan membuat konstruksi objek lebih mudah terutama jika Anda tidak menggunakan kerangka kerja DI. Service Locators adalah pola yang baik untuk mengelola dependensi statis eksternal , misalnya database yang Anda harus melewati ke setiap objek di lapisan akses data Anda.

Saat refactoring kode lama , seringkali lebih mudah untuk refactor ke Service Locator daripada ke Dependency Injection. Yang Anda lakukan hanyalah mengganti instantiations dengan pencarian layanan dan kemudian memalsukan layanan dalam pengujian unit Anda.

Namun, ada beberapa kerugian pada Service Locator. Mengetahui depandansi kelas lebih sulit karena dependensi tersembunyi dalam implementasi kelas, bukan pada konstruktor atau setter. Dan menciptakan dua objek yang bergantung pada implementasi berbeda dari layanan yang sama sulit atau tidak mungkin.

TLDR : Jika kelas Anda memiliki dependensi statis atau Anda sedang refactoring kode lama, Service Locator bisa dibilang lebih baik daripada DI.

Garrett Hall
sumber
12
Pencari Layanan menyembunyikan ketergantungan pada kode Anda . Itu bukan pola yang baik untuk digunakan.
Kyralessa
Ketika datang ke dependensi statis, saya lebih suka melihat fasad menampar mereka yang mengimplementasikan antarmuka. Ini kemudian dapat disuntikkan ketergantungan, dan mereka jatuh pada granat statis untuk Anda.
Erik Dietrich
@ Kirralessa Saya setuju, Service Locator memiliki banyak kerugian dan DI hampir selalu lebih disukai. Namun, saya percaya ada beberapa pengecualian terhadap aturan tersebut, seperti halnya semua prinsip pemrograman.
Garrett Hall
Penggunaan utama lokasi layanan yang diterima adalah dalam pola Strategi, di mana kelas "pemetik strategi" diberikan cukup logika untuk menemukan strategi yang akan digunakan, dan menyerahkannya kembali atau meneruskan panggilan ke sana. Bahkan dalam kasus ini, pemetik strategi dapat menjadi fasad untuk metode pabrik yang disediakan oleh wadah IoC, yang diberi logika yang sama; alasan mengapa Anda memutuskannya adalah untuk menempatkan logika di tempat yang seharusnya dan bukan tempat yang paling tersembunyi.
KeithS
Mengutip Martin Fowler, "Pilihan antara (DI dan Service Locator) kurang penting daripada prinsip memisahkan konfigurasi dari penggunaan". Gagasan bahwa DI adalah SELALU lebih baik adalah omong kosong. Jika suatu layanan digunakan secara global, itu lebih rumit dan rapuh untuk menggunakan DI. Selain itu, DI kurang menguntungkan untuk arsitektur plugin di mana implementasinya tidak diketahui sampai runtime. Pikirkan betapa canggungnya untuk selalu memberikan argumen tambahan ke Debug.WriteLine () dan sejenisnya!
Colin