Apa perbedaan praktis antara gaya injeksi ketergantungan?

12

Saya baru mengenal injeksi ketergantungan dan saya memiliki beberapa pertanyaan tentang gaya apa yang harus saya gunakan dalam aplikasi saya. Saya baru saja membaca Inversion of Control Containers dan pola Dependency Injection oleh Martin Fowler, tetapi saya tidak bisa mendapatkan perbedaan praktis antara konstruktor, setter, dan injeksi antarmuka.

Sepertinya saya bahwa alasan untuk menggunakan satu di atas yang lain hanya masalah pembersihan kode dan / atau kejelasan. Apa bedanya? Apakah ada kelebihan atau kekurangan yang kuat untuk menggunakan salah satu dari yang lain, atau hanya seperti yang saya katakan sebelumnya?

Menurut pendapat saya, injeksi konstruktor adalah yang paling intuitif dari semua, serta injeksi antarmuka adalah yang paling sedikit. Di sisi lain, setter injection adalah istilah jangka menengah, tetapi, apakah Anda seharusnya bisa mengubah instance objek dependensi yang awalnya Anda injeksi? Apakah gaya injeksi ini menjamin bahwa objek yang membutuhkan ketergantungan akan selalu disuntikkan? Saya tidak percaya, tapi tolong perbaiki saya jika saya salah.

ecampver
sumber
Tidak yakin apa lagi yang Anda temukan atau baca di sepanjang jalan. Saya menemukan beberapa utas yang serupa di sini dan di sini . Saya sendiri baru, dan akan penasaran dengan jawaban yang mungkin Anda dapatkan :)
@ user1766760 Anda harus membantu saya maka di sini, pertanyaan saya sedang dipilih untuk ditutup, dua suara lagi dan selesai !!! Pilih pertanyaan atau sesuatu, saya tidak tahu apa yang bisa dilakukan untuk menghindari penutupan.
ecampver
erm ... Saya sendiri yang baru jadi saya sendiri jadi saya tidak terlalu yakin bagaimana saya bisa membantu / mengapa ini ditutup (saya tidak melihat indikasi apa-apa ??). Jika saya berani menebak, mungkin itu bukan pertanyaan pemrograman khusus tetapi lebih merupakan diskusi?
Anda mungkin ingin sedikit memperluas pertanyaan. Ketergantungan injeksi adalah salah satu bentuk "Pembalikan Kontrol". Ada beberapa alternatif. Alternatif yang berguna tetapi matang untuk penyalahgunaan adalah Lokasi Layanan misalnya.
Ian

Jawaban:

12

Injeksi Konstruktor memiliki keunggulan yang menjadikan ketergantungan eksplisit dan memaksa klien untuk memberikan contoh. Itu juga dapat menjamin bahwa klien tidak dapat mengubah instance nanti. Satu kelemahan (kemungkinan) adalah Anda harus menambahkan parameter ke konstruktor.

Setter Injection memiliki keunggulan karena tidak perlu menambahkan parameter ke konstruktor. Itu juga tidak mengharuskan klien untuk mengatur instance. Ini berguna untuk dependensi opsional. Ini mungkin juga berguna jika Anda ingin kelas untuk membuat, misalnya, repositori data nyata secara default, dan kemudian dalam tes Anda bisa menggunakan setter untuk menggantinya dengan contoh pengujian.

Antarmuka Injeksi , sejauh yang saya tahu, tidak jauh berbeda dari injeksi setter. Dalam kedua kasus Anda (opsional) menetapkan ketergantungan yang dapat diubah nanti.

Pada akhirnya ini adalah masalah preferensi dan apakah ketergantungan diperlukan atau tidak . Secara pribadi, saya menggunakan injeksi konstruktor hampir secara eksklusif. Saya suka itu membuat dependensi kelas eksplisit dengan memaksa klien untuk memberikan contoh di konstruktor. Saya juga suka bahwa klien tidak dapat mengubah instance setelah fakta.

Sering kali, satu-satunya alasan saya untuk melewati dua implementasi terpisah adalah untuk pengujian. Dalam produksi, saya dapat lulus dalam DataRepository, tetapi dalam pengujian, saya akan lulus dalam a FakeDataRepository. Dalam hal ini saya biasanya akan memberikan dua konstruktor: satu tanpa parameter, dan lainnya yang menerima a IDataRepository. Kemudian, di dalam konstruktor tanpa parameter, saya akan membuat panggilan ke konstruktor kedua dan meneruskan a new DataRepository().

Berikut ini contoh dalam C #:


public class Foo
{
  private readonly IDataRepository dataRepository;

  public Foo() : this(new DataRepository())
  {
  }

  public Foo(IDataRespository dataRepository)
  {
    this.dataRepository = dataRepository;
  }
}

Ini dikenal sebagai Injeksi Ketergantungan Orang Miskin. Saya suka karena dalam kode klien produksi, saya tidak perlu mengulangi diri saya dengan memiliki beberapa pernyataan berulang yang terlihat seperti

var foo = new Foo(new DataRepository());
Namun, saya masih bisa meneruskan implementasi alternatif untuk pengujian. Saya menyadari bahwa dengan DIA Poor Man, saya membuat hardcoding ketergantungan saya, tetapi itu dapat diterima bagi saya karena saya kebanyakan menggunakan DI untuk pengujian.

jewewlett
sumber
terima kasih, itu cukup dekat dengan apa yang saya mengerti, tetapi masih, apakah ada skenario di mana Anda tidak dapat menggunakan injeksi konstruktor ?
ecampver
1
Anda mungkin tidak ingin menggunakan injeksi konstruktor untuk dependensi opsional. Saya tidak bisa memikirkan alasan lain untuk tidak menggunakannya.
jhewlett
Saya menggunakan injeksi setter properti secara khusus untuk mengisi beberapa kelas konfigurasi yang mencakup sejumlah besar nilai. Saya tidak menggunakannya di tempat lain. Saya selalu agak ragu tentang membuat kasus untuk parameter opsional karena ada peluang bagus itu pelanggaran aturan tanggung jawab tunggal. Tentu saja aturan dimaksudkan untuk dilanggar, jadi ...
Ian
@jhewlett - itu fantastis, saya telah mencari teknik stubbing sederhana yang bagus untuk pengujian unit yang tidak terlalu menyulitkan solusi saya - dan saya pikir inilah dia :)
Rocklan
2

Perbedaan antara konstruktor dan injeksi setter sudah dijelaskan di atas, jadi saya tidak akan menguraikan lebih lanjut tentang mereka.

Antarmuka injeksi adalah bentuk injeksi yang lebih maju yang berguna karena memungkinkan ketergantungan untuk diputuskan pada saat digunakan daripada selama inisialisasi objek yang akan menggunakannya. Ini memungkinkan sejumlah opsi berguna:

  • Ketergantungan dapat dicakup secara berbeda dengan objek yang disuntikkan; misalnya Anda dapat menggunakan injeksi antarmuka untuk memberikan objek yang ada satu per sesi pengguna atau per utas ke singleton global. Setiap kali objek membutuhkan dependensi, ia akan memanggil metode pengambil yang disediakan oleh framework, dan ini dapat mengembalikan hasil yang berbeda tergantung pada situasi di mana ia dipanggil.

  • Ini memungkinkan inisialisasi malas - tidak perlu ketergantungan diinisialisasi sampai akan digunakan

  • Ini memungkinkan dependensi untuk dimuat dari salinan cache ketika mereka ada atau diinisialisasi ulang ketika mereka tidak (misalnya menggunakan SoftReferencedi Jawa).

Jelas teknik-teknik canggih seperti ini memiliki kelemahan; dalam hal ini, masalah utama adalah kode menjadi kurang jelas (kelas yang digunakan dalam kode Anda menjadi abstrak, dan tidak ada implementasi nyata yang jelas, yang dapat membingungkan jika Anda tidak terbiasa) dan Anda menjadi lebih tergantung pada kerangka injeksi ketergantungan Anda (tentu saja masih memungkinkan untuk membuat objek Anda secara manual, tetapi lebih sulit daripada dengan gaya injeksi lainnya).

Jules
sumber