Saya minta maaf jika ini sepertinya pengulangan pertanyaan yang lain, tetapi setiap kali saya menemukan artikel mengenai topik tersebut, sebagian besar hanya berbicara tentang apa itu DI. Jadi, saya mendapatkan DI, tetapi saya mencoba memahami perlunya wadah IoC, yang tampaknya semua orang masuki. Apakah titik wadah IoC benar-benar hanya untuk "menyelesaikan otomatis" implementasi konkret dari dependensi? Mungkin kelas saya cenderung tidak memiliki beberapa dependensi dan mungkin itu sebabnya saya tidak melihat masalah besar, tetapi saya ingin memastikan bahwa saya memahami utilitas wadah dengan benar.
Saya biasanya memecah logika bisnis saya menjadi kelas yang mungkin terlihat seperti ini:
public class SomeBusinessOperation
{
private readonly IDataRepository _repository;
public SomeBusinessOperation(IDataRespository repository = null)
{
_repository = repository ?? new ConcreteRepository();
}
public SomeType Run(SomeRequestType request)
{
// do work...
var results = _repository.GetThings(request);
return results;
}
}
Jadi itu hanya memiliki satu ketergantungan, dan dalam beberapa kasus mungkin memiliki yang kedua atau ketiga, tetapi tidak terlalu sering. Jadi, apa pun yang memanggil ini dapat lewat repo sendiri atau mengizinkannya menggunakan repo default.
Sejauh pemahaman saya saat ini tentang wadah IoC, semua wadah lakukan adalah menyelesaikan IDataRepository. Tetapi jika hanya itu yang dilakukannya, maka saya tidak melihat satu ton nilai pun di dalamnya karena kelas operasional saya telah menentukan mundur ketika tidak ada ketergantungan yang lewat. Jadi satu-satunya manfaat lain yang dapat saya pikirkan adalah bahwa jika saya memiliki beberapa operasi seperti ini menggunakan repo fallback yang sama, saya bisa mengubah repo itu di satu tempat yang merupakan registry / pabrik / wadah. Dan itu hebat, tetapi apakah itu?
sumber
ConcreteRepository
dan (2) Anda dapat menyediakan dependensi tambahan untukConcreteRepository
(koneksi database akan umum, misalnya).Jawaban:
Kontainer IoC bukan tentang kasus di mana Anda memiliki satu ketergantungan. Ini tentang kasus di mana Anda memiliki 3 dependensi dan mereka memiliki beberapa dependensi yang memiliki dependensi dll.
Ini juga membantu Anda untuk memusatkan resolusi ketergantungan, dan manajemen siklus ketergantungan.
sumber
Ada sejumlah alasan mengapa Anda mungkin ingin menggunakan wadah IoC.
Dll tidak direferensikan
Anda dapat menggunakan wadah IoC untuk menyelesaikan kelas beton dari dll yang tidak direferensikan. Ini berarti bahwa Anda dapat mengambil dependensi sepenuhnya pada abstraksi - yaitu antarmuka.
Hindari penggunaan
new
Wadah IoC berarti bahwa Anda dapat sepenuhnya menghapus penggunaan
new
kata kunci untuk membuat kelas. Ini memiliki dua efek. Yang pertama adalah itu memisahkan kelas Anda. Yang kedua (yang terkait) adalah bahwa Anda dapat menjatuhkan ejekan untuk pengujian unit. Ini sangat berguna, terutama ketika Anda berinteraksi dengan proses yang berjalan lama.Menulis Terhadap Abstraksi
Menggunakan wadah IoC untuk menyelesaikan dependensi konkret Anda agar Anda dapat menulis kode Anda terhadap abstraksi, daripada menerapkan setiap kelas konkret yang Anda butuhkan saat dibutuhkan. Misalnya, Anda mungkin memerlukan kode Anda untuk membaca data dari database. Alih-alih menulis kelas interaksi basis data, Anda cukup menulis antarmuka untuknya dan mengkodekaninya. Anda dapat menggunakan tiruan untuk menguji fungsionalitas kode yang Anda kembangkan saat Anda mengembangkannya, daripada mengandalkan mengembangkan kelas interaksi basis data konkret sebelum Anda dapat menguji kode lainnya.
Hindari kode rapuh
Alasan lain untuk menggunakan wadah IoC adalah bahwa dengan mengandalkan wadah IoC untuk menyelesaikan dependensi Anda, Anda menghindari kebutuhan untuk mengubah setiap panggilan tunggal ke konstruktor kelas ketika Anda menambah atau menghapus dependensi. Kontainer IoC akan secara otomatis menyelesaikan dependensi Anda. Ini bukan masalah besar ketika Anda membuat kelas sekali, tetapi ini adalah masalah besar ketika Anda membuat kelas di seratus tempat.
Manajemen seumur hidup dan pembersihan sumber daya yang tidak dikelola
Alasan terakhir yang akan saya sebutkan adalah manajemen daya tahan objek. Kontainer IoC sering memberikan kemampuan untuk menentukan umur suatu objek. Masuk akal untuk menentukan masa pakai objek dalam wadah IoC daripada mencoba mengelolanya secara manual dalam kode. Manajemen seumur hidup manual bisa sangat sulit. Ini bisa berguna ketika berhadapan dengan benda yang membutuhkan pembuangan. Alih-alih mengelola pembuangan objek secara manual, beberapa wadah IoC akan mengelola pembuangan untuk Anda, yang dapat membantu mencegah kebocoran memori dan menyederhanakan basis kode Anda.
Masalah dengan kode sampel yang Anda berikan adalah bahwa kelas yang Anda tulis memiliki ketergantungan konkret pada kelas ConcreteRepository. Kontainer IoC akan menghapus ketergantungan itu.
sumber
Menurut prinsip tanggung jawab tunggal, setiap kelas harus hanya memiliki satu tanggung jawab tunggal. Membuat instance kelas baru hanyalah tanggung jawab lain, jadi Anda harus merangkum kode semacam ini dalam satu atau beberapa kelas. Anda dapat melakukannya menggunakan pola kreasi apa saja, misalnya pabrik, pembangun, wadah DI dll ...
Ada prinsip-prinsip lain seperti inversi kontrol dan inversi ketergantungan. Dalam konteks ini mereka terkait dengan Instansiasi dependensi. Mereka menyatakan bahwa kelas tingkat tinggi harus dipisahkan dari kelas tingkat rendah (dependensi) yang mereka gunakan. Kita dapat memisahkan hal-hal dengan membuat antarmuka. Jadi kelas tingkat rendah harus mengimplementasikan antarmuka spesifik dan kelas tingkat tinggi harus memanfaatkan instance kelas yang mengimplementasikan antarmuka ini. (catatan: Kendala antarmuka seragam REST menerapkan pendekatan yang sama pada tingkat sistem.)
Kombinasi prinsip-prinsip ini dengan contoh (maaf untuk kode berkualitas rendah, saya menggunakan beberapa bahasa ad-hoc alih-alih C #, karena saya tidak tahu itu):
Tidak ada SRP, tidak ada IoC
Lebih dekat ke SRP, tidak ada IoC
Ya SRP, tidak ada IoC
Ya SRP, ya IOC
Jadi kami akhirnya memiliki kode di mana Anda dapat mengganti setiap implementasi konkret dengan yang lain yang mengimplementasikan antarmuka ofc yang sama. Jadi ini bagus karena kelas yang berpartisipasi dipisahkan satu sama lain, mereka hanya tahu antarmuka. Keuntungan lain bahwa kode instantiation dapat digunakan kembali.
sumber