Kedua pola tersebut tampak seperti implementasi prinsip inversi kontrol. Artinya, suatu objek seharusnya tidak tahu bagaimana membangun ketergantungannya.
Dependency Injection (DI) tampaknya menggunakan konstruktor atau setter untuk "menyuntikkan" dependensinya.
Contoh menggunakan Injeksi Konstruktor:
//Foo Needs an IBar
public class Foo
{
private IBar bar;
public Foo(IBar bar)
{
this.bar = bar;
}
//...
}
Service Locator tampaknya menggunakan "wadah", yang memasang dependensinya dan memberikan bilah foo itu.
Contoh menggunakan Pencari Layanan:
//Foo Needs an IBar
public class Foo
{
private IBar bar;
public Foo()
{
this.bar = Container.Get<IBar>();
}
//...
}
Karena dependensi kita hanyalah objek itu sendiri, dependensi ini memiliki dependensi, yang bahkan memiliki lebih banyak dependensi, dan seterusnya dan seterusnya. Dengan demikian, Pembalikan Kontainer Kontrol (atau Kontainer DI) lahir. Contoh: Kastil Windsor, Ninject, Peta Struktur, Musim Semi, dll.)
Tapi Kontainer IOC / DI terlihat persis seperti Service Locator. Apakah menyebutnya Wadah DI adalah nama yang buruk? Apakah Kontainer IOC / DI hanyalah tipe lain dari Service Locator? Apakah nuansa pada kenyataan bahwa kita menggunakan Kontainer DI sebagian besar ketika kita memiliki banyak Ketergantungan?
sumber
Jawaban:
Perbedaannya mungkin tampak sedikit, tetapi bahkan dengan ServiceLocator, kelas masih bertanggung jawab untuk membuat dependensinya. Itu hanya menggunakan pencari lokasi layanan untuk melakukannya. Dengan DI, kelas diberikan dependensinya. Mereka tidak tahu, atau peduli dari mana mereka berasal. Salah satu hasil penting dari ini adalah bahwa contoh DI jauh lebih mudah untuk unit test - karena Anda dapat melewatinya mengejek implementasi objek dependennya. Anda dapat menggabungkan keduanya - dan menyuntikkan locator layanan (atau pabrik), jika Anda mau.
sumber
Saat Anda menggunakan pencari lokasi layanan, setiap kelas akan memiliki ketergantungan pada pencari lokasi layanan Anda. Ini tidak terjadi dengan injeksi ketergantungan. Injektor dependensi biasanya akan dipanggil hanya sekali pada saat startup untuk menyuntikkan dependensi ke beberapa kelas utama. Kelas-kelas yang bergantung pada kelas utama ini akan secara dependensi disuntikkan, hingga Anda memiliki grafik objek yang lengkap.
Perbandingan yang bagus: http://martinfowler.com/articles/injection.html
Jika injector dependensi Anda terlihat seperti pencari layanan, di mana kelas-kelas memanggil injector secara langsung, itu mungkin bukan injector dependensi, tetapi lebih sebagai pencari layanan.
sumber
Pelacak layanan menyembunyikan dependensi - Anda tidak dapat mengetahui dengan melihat objek apakah itu mengenai database atau tidak (misalnya) ketika mendapat koneksi dari pelacak. Dengan injeksi dependensi (setidaknya injeksi konstruktor) dependensi eksplisit.
Selain itu, pelacak layanan memecahkan enkapsulasi karena mereka menyediakan titik akses global ke dependensi objek lain. Dengan pencari layanan, seperti halnya singleton :
Dengan injeksi dependensi, setelah dependensi objek ditentukan, mereka di bawah kendali objek itu sendiri.
sumber
With dependency injection (at least constructor injection) the dependencies are explicit.
. Tolong jelaskan.Martin Fowler menyatakan :
Singkatnya: Service Locator dan Dependency Injection hanyalah implementasi dari Prinsip Ketergantungan Inversion.
Prinsip penting adalah "Bergantung pada Abstraksi, bukan pada Konkret". Ini akan membuat desain perangkat lunak Anda "longgar digabungkan", "extensible", "fleksibel".
Anda dapat menggunakan salah satu yang paling sesuai dengan kebutuhan Anda. Untuk aplikasi besar, memiliki basis kode yang besar, Anda sebaiknya menggunakan Service Locator, karena Ketergantungan Injeksi akan membutuhkan lebih banyak perubahan pada basis kode Anda.
Anda dapat memeriksa pos ini: Pembalikan Ketergantungan: Pencari Layanan atau Injeksi Ketergantungan
Juga yang klasik: Pembalikan Kontain Kontrol dan pola Injeksi Ketergantungan oleh Martin Fowler
Merancang Kelas yang Dapat Digunakan Kembali oleh Ralph E. Johnson & Brian Foote
Namun, yang membuka mata saya adalah: ASP.NET MVC: Resolve or Inject? Itulah Masalahnya ... oleh Dino Esposito
sumber
Kelas yang menggunakan konstruktor DI menunjukkan untuk mengkonsumsi kode bahwa ada dependensi yang harus dipenuhi. Jika kelas menggunakan SL secara internal untuk mengambil dependensi seperti itu, kode yang mengkonsumsi tidak mengetahui dependensi. Ini mungkin di permukaan tampak lebih baik, tetapi sebenarnya membantu untuk mengetahui adanya ketergantungan eksplisit. Lebih baik dari sudut pandang arsitektur. Dan ketika melakukan pengujian, Anda harus tahu apakah suatu kelas membutuhkan dependensi tertentu, dan konfigurasikan SL untuk menyediakan versi palsu yang sesuai dari dependensi tersebut. Dengan DI, lakukan umpan palsu. Bukan perbedaan besar, tetapi ada di sana.
DI dan SL dapat bekerja bersama. Berguna untuk memiliki lokasi sentral untuk dependensi umum (mis. Pengaturan, logger, dll). Diberikan kelas menggunakan deps seperti itu, Anda dapat membuat konstruktor "nyata" yang menerima deps, dan konstruktor default (tanpa parameter) yang mengambil dari SL dan meneruskan ke konstruktor "nyata".
EDIT: dan, tentu saja, ketika Anda menggunakan SL, Anda memperkenalkan beberapa kopling ke komponen itu. Yang ironis, karena gagasan fungsi tersebut adalah untuk mendorong abstraksi dan mengurangi kopling. Kekhawatiran bisa seimbang, dan itu tergantung pada berapa banyak tempat yang Anda perlukan untuk menggunakan SL. Jika dilakukan seperti yang disarankan di atas, cukup di konstruktor kelas default.
sumber
Keduanya adalah teknik implementasi IoC. Ada juga pola lain yang mengimplementasikan Inversion of Control:
Pencari Lokasi Layanan dan Kontainer DI tampak lebih mirip, keduanya menggunakan wadah untuk menentukan dependensi, yang memetakan abstraksi ke implementasi konkret.
Perbedaan utama adalah bagaimana dependensi berada, di Service Locator, kode klien meminta dependensi, dalam DI Container kami menggunakan wadah untuk membuat semua objek dan menyuntikkan dependensi sebagai parameter konstruktor (atau properti).
sumber
Dalam proyek terakhir saya, saya menggunakan keduanya. Saya menggunakan injeksi ketergantungan untuk testabilitas unit. Saya menggunakan pencari lokasi untuk menyembunyikan implementasi dan bergantung pada wadah IoC saya. dan ya! Setelah Anda menggunakan salah satu wadah IoC (Unity, Ninject, Windsor Castle) Anda bergantung padanya. Dan setelah usang atau karena alasan tertentu jika Anda ingin menukar itu, Anda akan / mungkin perlu mengubah implementasi Anda - setidaknya komposisi root. Tapi pencari layanan abstrak fase itu.
Bagaimana Anda tidak akan bergantung pada wadah IoC Anda? Entah Anda harus membungkusnya sendiri (yang merupakan ide buruk) atau Anda menggunakan Service Locator untuk mengkonfigurasi wadah IoC Anda. Jadi Anda akan memberi tahu locator layanan untuk mendapatkan antarmuka yang Anda butuhkan, dan itu akan memanggil wadah IoC yang dikonfigurasi untuk mengambil antarmuka itu.
Dalam kasus saya, saya menggunakan ServiceLocator yang merupakan komponen kerangka kerja. Dan gunakan Unity untuk wadah IoC. Jika di masa depan saya harus menukar wadah IoC saya ke Ninject perlu saya lakukan adalah saya perlu mengkonfigurasi pencari Layanan saya untuk menggunakan Ninject bukan Unity. Migrasi mudah.
Berikut ini adalah artikel yang bagus menjelaskan skenario ini; http://www.johandekoning.nl/index.php/2013/03/03/dont-wrap-your-ioc-container/
sumber
Saya pikir keduanya bekerja bersama.
Injeksi ketergantungan berarti Anda mendorong beberapa kelas / antarmuka dependen ke kelas konsumsi (biasanya ke konstruktornya). Ini memisahkan dua kelas melalui antarmuka dan berarti kelas konsumsi dapat bekerja dengan banyak jenis implementasi "ketergantungan yang disuntikkan".
Peran pencari layanan adalah untuk menyatukan implementasi Anda. Anda mengatur pelacak layanan melalui beberapa tegap boot pada awal program Anda. Bootstrap adalah proses mengaitkan jenis implementasi ke abstrak / antarmuka tertentu. Yang akan dibuat untuk Anda saat run time. (berdasarkan konfigurasi Anda atau bootstrap). Jika Anda belum menerapkan injeksi ketergantungan, akan sangat sulit untuk menggunakan pencari lokasi layanan atau wadah IOC.
sumber
Satu alasan untuk ditambahkan, terinspirasi oleh pembaruan dokumentasi yang kami buat untuk proyek MEF minggu lalu (saya membantu membangun MEF).
Setelah sebuah aplikasi terdiri dari ribuan komponen yang berpotensi, sulit untuk menentukan apakah komponen tertentu dapat dibuat dengan benar. Dengan "instantiated dengan benar", maksud saya bahwa dalam contoh ini berdasarkan pada
Foo
komponen, contoh dariIBar
dan akan tersedia, dan bahwa komponen yang menyediakannya akan:Dalam contoh kedua yang Anda berikan, di mana konstruktor pergi ke wadah IoC untuk mengambil dependensinya, satu-satunya cara Anda dapat menguji bahwa instance
Foo
dapat dapat dipakai dengan benar dengan konfigurasi runtime aktual aplikasi Anda adalah untuk benar - benar membangun Itu .Ini memiliki semua jenis efek samping yang aneh pada waktu pengujian, karena kode yang akan bekerja pada saat runtime tidak akan selalu bekerja di bawah test harness. Mocks tidak akan melakukan apa-apa, karena konfigurasi sebenarnya adalah hal yang perlu kita uji, bukan pengaturan waktu pengujian.
Akar masalah ini adalah perbedaan yang sudah dipanggil oleh @Jon: menyuntikkan dependensi melalui konstruktor bersifat deklaratif, sedangkan versi kedua menggunakan pola Service Locator yang imperatif.
Wadah IoC, bila digunakan dengan hati-hati, secara statis dapat menganalisis konfigurasi runtime aplikasi Anda tanpa benar-benar membuat instance komponen yang terlibat. Banyak wadah populer menyediakan beberapa variasi; Microsoft.Composition , yang merupakan versi MEF penargetan .NET 4.5 web dan aplikasi gaya Metro, menyediakan
CompositionAssert
sampel dalam dokumentasi wiki. Dengan menggunakannya, Anda dapat menulis kode seperti:(Lihat contoh ini ).
Dengan memverifikasi Root Komposisi aplikasi Anda pada waktu pengujian Anda berpotensi menangkap beberapa kesalahan yang mungkin lolos pengujian di kemudian hari dalam proses.
Semoga ini merupakan tambahan yang menarik untuk set jawaban yang komprehensif untuk topik ini!
sumber
Catatan: Saya tidak benar-benar menjawab pertanyaan itu. Tapi saya merasa bahwa ini dapat berguna bagi pelajar baru dari pola Injeksi Ketergantungan yang bingung tentang hal itu dengan pola Service Locator (anti-) yang kebetulan tersandung ke halaman ini.
Saya tahu perbedaan antara Service Locator (tampaknya dianggap sebagai anti-pola sekarang) dan pola Ketergantungan Injeksi dan dapat memahami contoh konkret setiap pola, namun saya bingung dengan contoh yang menunjukkan locator layanan di dalam konstruktor (asumsikan kami ' sedang melakukan injeksi konstruktor).
"Service Locator" sering digunakan baik sebagai nama pola, dan sebagai nama untuk merujuk ke objek (anggap juga) digunakan dalam pola itu untuk mendapatkan objek tanpa menggunakan operator baru. Sekarang, jenis objek yang sama juga dapat digunakan di root komposisi untuk melakukan injeksi ketergantungan, dan di situlah kebingungan muncul.
Intinya yang perlu diperhatikan adalah bahwa Anda mungkin menggunakan objek pencari lokasi di dalam konstruktor DI, tetapi Anda tidak menggunakan "pola Penentu Lokasi Layanan". Itu kurang membingungkan jika seseorang merujuknya sebagai objek wadah IoC, karena Anda mungkin menduga bahwa mereka pada dasarnya melakukan hal yang sama (perbaiki saya jika saya salah).
Apakah itu disebut sebagai pencari lokasi (atau hanya pencari), atau sebagai wadah IoC (atau hanya wadah) tidak ada bedanya seperti yang Anda duga karena mereka mungkin merujuk pada abstraksi yang sama (perbaiki saya jika saya salah ). Hanya saja menyebutnya locator layanan menunjukkan bahwa seseorang menggunakan anti-pola Locator Layanan bersama dengan pola Injeksi Ketergantungan.
IMHO, menamakannya 'locator' bukan 'location' atau 'locating', juga dapat menyebabkan orang kadang-kadang berpikir bahwa locator layanan dalam sebuah artikel merujuk pada wadah Service Locator, dan bukan pola Service Locator (anti-) , terutama ketika ada pola terkait yang disebut Injeksi Ketergantungan dan bukan Ketergantungan Injector.
sumber
Dalam kasus yang terlalu disederhanakan ini tidak ada perbedaan dan mereka dapat digunakan secara bergantian. Namun, masalah dunia nyata tidak sesederhana itu. Asumsikan saja bahwa kelas Bar itu sendiri memiliki dependensi lain bernama D. Dalam hal itu pencari lokasi Anda tidak akan dapat menyelesaikan ketergantungan itu dan Anda harus instantiate dalam kelas D; karena itu adalah tanggung jawab kelas Anda untuk membuat instance dependensi mereka. Bahkan akan lebih buruk jika kelas D itu sendiri memiliki dependensi lain dan dalam situasi dunia nyata biasanya menjadi lebih rumit dari itu. Dalam skenario seperti itu DI adalah solusi yang lebih baik daripada ServiceLocator.
sumber
bar
kelas itu sendiri memiliki ketergantungan, makabar
juga akan memiliki pencari lokasi, itulah inti menggunakan DI / IoC.Apa perbedaan (jika ada) antara Injeksi Ketergantungan dan Pencari Layanan? Kedua pola itu bagus dalam menerapkan prinsip Ketergantungan Inversi. Pola Service Locator lebih mudah digunakan dalam basis kode yang ada karena membuat desain keseluruhan lebih longgar tanpa memaksakan perubahan pada antarmuka publik. Untuk alasan yang sama, kode yang didasarkan pada pola Locator Layanan kurang dapat dibaca daripada kode setara yang didasarkan pada Injeksi Ketergantungan.
Pola Injeksi Ketergantungan membuatnya jelas karena tanda tangan yang dependensi kelas (atau metode) akan miliki. Karena alasan ini, kode yang dihasilkan lebih bersih dan lebih mudah dibaca.
sumber
Mengikuti konsepsi sederhana memberi saya pemahaman yang lebih jelas tentang perbedaan antara Service Locator dan DI Container:
Service Locator digunakan di konsumen dan menarik layanan dengan ID dari beberapa penyimpanan dengan permintaan konsumen langsung
DI Container terletak di suatu tempat di luar dan membutuhkan layanan dari beberapa penyimpanan dan mendorongnya ke konsumen (tidak peduli melalui konstruktor atau melalui metode)
Namun, kita dapat berbicara tentang perbedaan antara ini hanya dalam konteks penggunaan konsumen yang konkret. Ketika Service Locator dan DI Container digunakan dalam komposisi root, mereka hampir mirip.
sumber
Wadah DI adalah superset pencari layanan. Ini dapat digunakan untuk menemukan layanan , dengan kemampuan tambahan perakitan (kabel) injeksi ketergantungan .
sumber
Untuk catatan
Kecuali Anda benar-benar membutuhkan antarmuka (antarmuka tersebut digunakan oleh lebih dari satu kelas), Anda TIDAK HARUS MENGGUNAKANNYA . Dalam hal ini, IBar memungkinkan memanfaatkan kelas layanan apa pun, yang mengimplementasikannya. Namun, biasanya, Interface ini akan digunakan oleh satu kelas.
Mengapa ide buruk menggunakan antarmuka ?. Karena sangat sulit untuk di-debug.
Misalnya, misalkan "bilah" contoh gagal, pertanyaan: kelas mana yang gagal ?. Kode mana yang harus saya perbaiki? Tampilan sederhana, mengarah ke Antarmuka, dan di sinilah jalan saya berakhir.
Sebaliknya, jika kode menggunakan dependensi keras maka mudah untuk men-debug kesalahan.
Jika "bar" gagal, maka saya harus memeriksa dan menyalakan kelas BarService.
sumber
contract
dan hanya mendefinisikan perilaku bukan tindakan. Alih-alih melewati objek aktual, hanya antarmuka yang dibagikan sehingga konsumen tidak mengakses sisa objek Anda. Juga untuk pengujian unit, akan membantu untuk menguji hanya bagian yang perlu diuji. Saya kira pada waktunya Anda akan memahami manfaatnya.