Tolong jual saya di wadah IoC

17

Saya telah melihat beberapa merekomendasikan penggunaan wadah IoC dalam kode. Motivasinya sederhana. Ambil kode injeksi ketergantungan berikut:

class UnitUnderTest
{
    std::auto_ptr<Dependency> d_;
public:
    UnitUnderTest(
        std::auto_ptr<Dependency> d = std::auto_ptr<Dependency>(new ConcreteDependency)
    ) : d_(d)
    {
    }
};


TEST(UnitUnderTest, Example)
{
    std::auto_ptr<Dependency> dep(new MockDependency);
    UnitUnderTest uut(dep);
    //Test here
}

Ke:

class UnitUnderTest
{
    std::auto_ptr<Dependency> d_;
public:
    UnitUnderTest()
    {
        d_.reset(static_cast<Dependency *>(IocContainer::Get("Dependency")));
    }
};


TEST(UnitUnderTest, Example)
{
    UnitUnderTest uut;
    //Test here
}

//Config for IOC container normally
<Dependency>ConcreteDependency</Dependency>

//Config for IOC container for testing
<Dependency>MockDependency</Dependency>

(Di atas adalah contoh C ++ hipotetis tentu saja)

Sementara saya setuju bahwa ini menyederhanakan antarmuka kelas dengan menghapus parameter konstruktor dependensi, saya pikir penyembuhannya lebih buruk daripada penyakit karena beberapa alasan. Pertama, dan ini yang besar bagi saya, ini membuat program Anda tergantung pada file konfigurasi eksternal. Jika Anda membutuhkan penyebaran biner tunggal, Anda tidak bisa menggunakan wadah seperti ini. Masalah kedua adalah bahwa API sekarang lemah dan lebih buruk, diketik dengan ketat . Buktinya (dalam contoh hipotetis ini) adalah argumen string ke wadah IoC, dan para pemeran pada hasilnya.

Jadi .. adakah manfaat lain dari menggunakan wadah semacam ini atau apakah saya hanya tidak setuju dengan mereka yang merekomendasikan wadah tersebut?

Billy ONeal
sumber
1
Kode sampel terlihat seperti contoh yang sangat buruk dari implementasi IoC. Saya hanya akrab dengan C # tetapi pasti ada cara untuk memiliki injeksi konstruktor dan konfigurasi program dalam C ++ juga?
rmac

Jawaban:

12

Dalam aplikasi besar dengan banyak lapisan dan banyak bagian yang bergerak, kelemahannya mulai terlihat sangat kecil jika dibandingkan dengan kelebihannya.

Wadah memang "menyederhanakan antarmuka" kelas, tetapi melakukannya dengan cara yang sangat penting. Wadah adalah solusi untuk masalah yang diciptakan injeksi ketergantungan, yang merupakan kebutuhan untuk meneruskan ketergantungan di semua tempat, turun melalui grafik objek dan melintasi area fungsional. Anda memiliki satu contoh kecil di sini yang memiliki satu ketergantungan - bagaimana jika objek ini memiliki tiga dependensi, dan objek yang bergantung padanya memiliki beberapa objek yang bergantung padanya , dan seterusnya? Tanpa wadah, objek di atas rantai ketergantungan tersebut akhirnya menjadi bertanggung jawab untuk melacak semua dependensi di seluruh aplikasi.

Ada berbagai jenis wadah juga. Tidak semuanya diketik secara ketat, dan tidak semuanya memerlukan file konfigurasi.

nlawalker
sumber
3
Tapi proyek besar membuat masalah yang sudah saya sebutkan lebih buruk . Jika proyek besar, file konfigurasi menjadi magnet ketergantungan besar itu sendiri, dan bahkan menjadi lebih mudah untuk memiliki satu kesalahan ketik untuk perilaku yang tidak terdefinisi saat runtime. (mis. memiliki salah ketik dalam file config akan menyebabkan para pemain menyebabkan perilaku yang tidak terdefinisi jika tipe yang salah dikembalikan). Adapun dependensi dependensi, itu tidak penting di sini. Entah konstruktor mengurus membuatnya, atau tes akan mengejek ketergantungan tingkat atas.
Billy ONeal
... Lanjutan ... Ketika program tidak sedang diuji, ketergantungan konkret default akan dipakai pada setiap langkah. Dengan jenis wadah lain, apakah Anda memiliki beberapa contoh?
Billy ONeal
4
TBH Saya tidak punya banyak pengalaman dengan implementasi DI, tetapi lihatlah MEF di .NET, yang bisa tetapi tidak harus diketik secara ketat, tidak memiliki file konfigurasi, dan implementasi konkret dari antarmuka "terdaftar" di kelas itu sendiri. BTW, ketika Anda mengatakan: "konstruktor merawat membuat mereka" - jika itu yang Anda lakukan (alias "injeksi konstruktor orang miskin"), maka Anda tidak perlu wadah. Keuntungan dari wadah daripada melakukan itu adalah bahwa wadah memusatkan informasi tentang semua dependensi itu.
nlawalker
+1 untuk komentar terakhir - kalimat terakhir ada jawabannya :)
Billy ONeal
1
Jawaban bagus yang membantu saya memahami seluruh pokok permasalahan. Intinya bukan hanya menyederhanakan pelat tungku, tetapi memungkinkan elemen di bagian atas rantai ketergantungan sama naifnya dengan elemen di bagian bawah.
Christopher Berman
4

Kerangka kerja Guice IoC dari Java tidak bergantung pada file konfigurasi tetapi pada kode konfigurasi . Ini berarti bahwa konfigurasi adalah kode yang tidak berbeda dari kode yang membuat aplikasi Anda yang sebenarnya, dan dapat di refactored dll.

Saya percaya bahwa Guice adalah kerangka Java IoC yang akhirnya mendapatkan konfigurasi yang benar.


sumber
Apakah ada contoh serupa untuk C ++?
Billy ONeal
@ Billy, saya tidak cukup akrab dengan C ++ untuk bisa mengatakan.
0

Jawaban SO yang luar biasa dari Ben Scheirman ini merinci beberapa contoh kode dalam C #; beberapa keuntungan dari wadah IOC (DI) adalah:

  • Rantai dependensi Anda dapat menjadi bersarang, dan dengan cepat menjadi sulit untuk memasang mereka secara manual.
  • Memungkinkan penggunaan pemrograman berorientasi aspek .
  • Transaksi basis data deklaratif & bersarang.
  • Unit kerja deklaratif & bersarang.
  • Penebangan.
  • Kondisi Pra / Pasca (Desain oleh Kontrak).
dodgy_coder
sumber
1
Saya tidak melihat bagaimana hal-hal itu tidak dapat diimplementasikan dengan injeksi konstruktor sederhana.
Billy ONeal
Dengan desain yang bagus, injeksi konstruktor atau metode lain mungkin cukup untuk Anda; keuntungan dari wadah IoC ini mungkin hanya dalam kasus tertentu. Contoh yang diberikan dengan INotifyPropertyChanged dalam proyek WPF adalah salah satu contohnya.
dodgy_coder