Baru-baru ini saya membaca artikel Mark Seemann tentang anti-pola Service Locator.
Penulis menunjukkan dua alasan utama mengapa ServiceLocator merupakan anti-pola:
Masalah penggunaan API (yang saya baik-baik saja)
Ketika kelas menggunakan pencari Layanan, sangat sulit untuk melihat ketergantungannya karena, dalam banyak kasus, kelas hanya memiliki satu konstruktor PARAMETERLESS. Berbeda dengan ServiceLocator, pendekatan DI secara eksplisit mengekspos dependensi melalui parameter konstruktor sehingga dependensi mudah dilihat di IntelliSense.Masalah pemeliharaan (yang membuat saya
bingung ) Perhatikan contoh berikut
Kami memiliki kelas 'MyType' yang menggunakan pendekatan pencari lokasi:
public class MyType
{
public void MyMethod()
{
var dep1 = Locator.Resolve<IDep1>();
dep1.DoSomething();
}
}
Sekarang kami ingin menambahkan ketergantungan lain ke kelas 'MyType'
public class MyType
{
public void MyMethod()
{
var dep1 = Locator.Resolve<IDep1>();
dep1.DoSomething();
// new dependency
var dep2 = Locator.Resolve<IDep2>();
dep2.DoSomething();
}
}
Dan di sinilah kesalahpahaman saya dimulai. Penulis berkata:
Menjadi jauh lebih sulit untuk mengetahui apakah Anda memperkenalkan perubahan yang menghancurkan atau tidak. Anda perlu memahami seluruh aplikasi di mana Service Locator digunakan, dan compiler tidak akan membantu Anda.
Tapi tunggu sebentar, jika kita menggunakan pendekatan DI, kita akan memperkenalkan ketergantungan dengan parameter lain dalam konstruktor (dalam kasus injeksi konstruktor). Dan masalahnya akan tetap ada. Jika kita mungkin lupa menyiapkan ServiceLocator, maka kita mungkin lupa menambahkan pemetaan baru dalam wadah IoC kita dan pendekatan DI akan memiliki masalah run-time yang sama.
Juga, penulis menyebutkan tentang kesulitan tes unit. Tapi, bukankah kita memiliki masalah dengan pendekatan DI? Tidakkah kita perlu memperbarui semua tes yang membuat instance kelas itu? Kami akan memperbaruinya agar lulus dependensi baru yang dibuat-buat hanya untuk membuat pengujian kami dapat disusun. Dan saya tidak melihat manfaat apa pun dari pembaruan dan pengeluaran waktu itu.
Saya tidak mencoba mempertahankan pendekatan Service Locator. Tetapi kesalahpahaman ini membuat saya berpikir bahwa saya kehilangan sesuatu yang sangat penting. Bisakah seseorang menghilangkan keraguan saya?
UPDATE (RINGKASAN):
Jawaban untuk pertanyaan saya "Apakah Pencari Lokasi Layanan merupakan anti-pola" sangat bergantung pada keadaan. Dan saya pasti tidak akan menyarankan untuk mencoretnya dari daftar alat Anda. Ini mungkin menjadi sangat berguna ketika Anda mulai berurusan dengan kode warisan. Jika Anda cukup beruntung berada di awal proyek Anda, maka pendekatan DI mungkin merupakan pilihan yang lebih baik karena memiliki beberapa keunggulan dibandingkan Service Locator.
Dan inilah perbedaan utama yang meyakinkan saya untuk tidak menggunakan Service Locator untuk proyek baru saya:
- Paling jelas dan penting: Service Locator menyembunyikan dependensi kelas
- Jika Anda menggunakan beberapa kontainer IoC, kemungkinan akan memindai semua konstruktor saat startup untuk memvalidasi semua dependensi dan memberi Anda umpan balik langsung tentang pemetaan yang hilang (atau konfigurasi yang salah); ini tidak mungkin jika Anda menggunakan container IoC Anda sebagai Service Locator
Untuk detailnya, baca jawaban luar biasa yang diberikan di bawah ini.
Jawaban:
Jika Anda mendefinisikan pola sebagai anti-pola hanya karena ada beberapa situasi di mana ia tidak cocok, maka YA itu pola anti. Tapi dengan alasan itu semua pola juga akan menjadi anti pola.
Sebagai gantinya kita harus melihat apakah ada penggunaan pola yang valid, dan untuk Service Locator ada beberapa kasus penggunaan. Tapi mari kita mulai dengan melihat contoh yang telah Anda berikan.
public class MyType { public void MyMethod() { var dep1 = Locator.Resolve<IDep1>(); dep1.DoSomething(); // new dependency var dep2 = Locator.Resolve<IDep2>(); dep2.DoSomething(); } }
Mimpi buruk pemeliharaan dengan kelas tersebut adalah bahwa dependensi disembunyikan. Jika Anda membuat dan menggunakan kelas itu:
var myType = new MyType(); myType.MyMethod();
Anda tidak mengerti bahwa itu memiliki ketergantungan jika disembunyikan menggunakan lokasi layanan. Sekarang, jika kita menggunakan injeksi ketergantungan:
public class MyType { public MyType(IDep1 dep1, IDep2 dep2) { } public void MyMethod() { dep1.DoSomething(); // new dependency dep2.DoSomething(); } }
Anda dapat langsung melihat dependensi dan tidak dapat menggunakan kelas sebelum memuaskannya.
Dalam garis aplikasi bisnis yang khas, Anda harus menghindari penggunaan lokasi layanan karena alasan itu. Ini harus menjadi pola yang akan digunakan saat tidak ada pilihan lain.
Apakah polanya anti-pola?
Tidak.
Misalnya, pembalikan wadah kontrol tidak akan bekerja tanpa lokasi layanan. Begitulah cara mereka menyelesaikan layanan secara internal.
Tetapi contoh yang jauh lebih baik adalah ASP.NET MVC dan WebApi. Menurut Anda, apa yang memungkinkan injeksi ketergantungan di pengontrol? Benar - lokasi layanan.
Pertanyaan Anda
Ada dua masalah yang lebih serius:
Dengan injeksi konstruktor menggunakan wadah Anda mendapatkannya secara gratis.
Itu benar. Tetapi dengan injeksi konstruktor Anda tidak perlu memindai seluruh kelas untuk mencari tahu dependensi mana yang hilang.
Dan beberapa container yang lebih baik juga memvalidasi semua dependensi saat startup (dengan memindai semua konstruktor). Jadi dengan container tersebut, Anda mendapatkan error runtime secara langsung, dan bukan di beberapa titik temporal selanjutnya.
Tidak. Karena Anda tidak memiliki ketergantungan ke pencari layanan statis. Sudahkah Anda mencoba mendapatkan pengujian paralel yang bekerja dengan dependensi statis? Ini tidak menyenangkan.
sumber
Saya juga ingin menunjukkan bahwa JIKA Anda memfaktorkan ulang kode warisan bahwa pola Pencari Layanan tidak hanya bukan anti-pola, tetapi juga merupakan kebutuhan praktis. Tidak seorang pun akan mengayunkan tongkat ajaib pada jutaan baris kode dan tiba-tiba semua kode itu akan siap. Jadi jika Anda ingin mulai memperkenalkan DI ke basis kode yang sudah ada, sering kali Anda akan mengubah sesuatu menjadi layanan DI secara perlahan, dan kode yang mereferensikan layanan ini seringkali BUKAN menjadi layanan DI. Oleh karena itu, layanan MEREKA perlu menggunakan Penunjuk Lokasi Layanan untuk mendapatkan contoh layanan tersebut yang TELAH dikonversi untuk menggunakan DI.
Jadi ketika refactoring aplikasi warisan yang besar untuk mulai menggunakan konsep DI saya akan mengatakan bahwa Service Locator BUKAN hanya anti-pola, tapi itu adalah satu-satunya cara untuk secara bertahap menerapkan konsep DI ke basis kode.
sumber
Dari sudut pandang pengujian, Service Locator buruk. Lihat penjelasan bagus Misko Hevery tentang Google Tech Talk dengan contoh kode http://youtu.be/RlfLCWKxHJ0 mulai menit 8:45. Saya menyukai analoginya: jika Anda membutuhkan $ 25, mintalah uang secara langsung daripada memberikan dompet Anda dari mana uang akan diambil. Dia juga membandingkan Service Locator dengan tumpukan jerami yang memiliki jarum yang Anda butuhkan dan tahu cara mengambilnya. Kelas yang menggunakan Service Locator sulit digunakan kembali karena itu.
sumber
Ada 2 alasan berbeda mengapa penggunaan pencari lokasi buruk dalam hal ini.
Biasa dan sederhana: Kelas dengan pencari lokasi di dalamnya lebih sulit untuk digunakan kembali daripada kelas yang menerima dependensinya melalui konstruktornya.
sumber
Pengetahuan saya tidak cukup baik untuk menilai ini, tetapi secara umum, saya pikir jika sesuatu memiliki kegunaan dalam situasi tertentu, itu tidak berarti itu tidak bisa menjadi anti-pola. Terutama, ketika Anda berurusan dengan pustaka pihak ketiga, Anda tidak memiliki kendali penuh pada semua aspek dan Anda mungkin akan menggunakan solusi yang bukan yang terbaik.
Berikut adalah paragraf dari Adaptive Code Via C # :
sumber
Penulis beralasan bahwa "kompilator tidak akan membantu Anda" - dan itu benar. Saat Anda berkenan pada sebuah kelas, Anda pasti ingin memilih antarmukanya dengan hati-hati - di antara tujuan lain untuk membuatnya se-independen ... seperti yang masuk akal.
Dengan meminta klien menerima referensi ke layanan (ke dependensi) melalui antarmuka eksplisit, Anda
Anda benar bahwa DI memiliki masalah / kekurangannya, tetapi keuntungan yang disebutkan sejauh ini lebih besar daripada mereka ... IMO. Anda benar, bahwa dengan DI ada ketergantungan yang diperkenalkan di antarmuka (konstruktor) - tetapi ini mudah-mudahan ketergantungan yang Anda butuhkan dan yang ingin Anda buat terlihat dan dapat diperiksa.
sumber
Ya, pencari lokasi adalah anti-pola yang melanggar enkapsulasi dan solid .
sumber