Apa manfaat dari wadah injeksi ketergantungan?

104

Saya memahami manfaat injeksi ketergantungan itu sendiri. Mari kita ambil contoh Spring. Saya juga memahami manfaat fitur Spring lainnya seperti AOP, helper dari berbagai jenis, dll. Saya hanya ingin tahu, apa saja manfaat konfigurasi XML seperti:

<bean id="Mary" class="foo.bar.Female">
  <property name="age" value="23"/>
</bean>
<bean id="John" class="foo.bar.Male">
  <property name="girlfriend" ref="Mary"/>
</bean>

dibandingkan dengan kode java lama biasa seperti:

Female mary = new Female();
mary.setAge(23);
Male john = new Male();
john.setGirlfriend(mary);

yang lebih mudah di-debug, waktu kompilasi diperiksa dan dapat dipahami oleh siapa saja yang hanya mengetahui java. Jadi apa tujuan utama kerangka kerja injeksi ketergantungan? (atau sepotong kode yang menunjukkan manfaatnya.)


UPDATE:
Dalam kasus

IService myService;// ...
public void doSomething() {  
  myService.fetchData();
}

Bagaimana kerangka kerja IoC dapat menebak implementasi myService mana yang ingin saya masukkan jika ada lebih dari satu? Jika hanya ada satu implementasi dari antarmuka yang diberikan, dan saya membiarkan wadah IoC secara otomatis memutuskan untuk menggunakannya, itu akan rusak setelah implementasi kedua muncul. Dan jika hanya ada satu kemungkinan implementasi antarmuka, maka Anda tidak perlu memasukkannya.

Akan sangat menarik untuk melihat bagian kecil konfigurasi untuk IoC yang menunjukkan manfaatnya. Saya telah menggunakan Spring untuk sementara waktu dan saya tidak dapat memberikan contoh seperti itu. Dan saya dapat menunjukkan satu baris yang menunjukkan manfaat hibernate, dwr, dan framework lain yang saya gunakan.


UPDATE 2:
Saya menyadari bahwa konfigurasi IoC dapat diubah tanpa kompilasi ulang. Apakah ini benar-benar ide yang bagus? Saya dapat memahami ketika seseorang ingin mengubah kredensial DB tanpa kompilasi ulang - dia mungkin bukan pengembang. Dalam praktik Anda, seberapa sering orang lain selain pengembang mengubah konfigurasi IoC? Saya pikir untuk pengembang tidak ada upaya untuk mengkompilasi ulang kelas tertentu daripada mengubah konfigurasi. Dan untuk non-pengembang Anda mungkin ingin membuat hidupnya lebih mudah dan menyediakan beberapa file konfigurasi yang lebih sederhana.


PEMBARUAN 3:

Konfigurasi eksternal pemetaan antara antarmuka dan implementasi konkretnya

Apa bagusnya membuatnya menjadi ekstenal? Anda tidak membuat semua kode Anda eksternal, sementara Anda pasti bisa - cukup letakkan di file ClassName.java.txt, baca dan kompilasi secara manual dengan cepat - wow, Anda menghindari kompilasi ulang. Mengapa kompilasi harus dihindari ?!

Anda menghemat waktu pengkodean karena Anda memberikan pemetaan secara deklaratif, bukan dalam kode prosedural

Saya mengerti bahwa terkadang pendekatan deklaratif menghemat waktu. Misalnya, saya mendeklarasikan hanya sekali pemetaan antara properti kacang dan kolom DB dan hibernasi menggunakan pemetaan ini saat memuat, menyimpan, membangun SQL berdasarkan HSQL, dll. Di sinilah pendekatan deklaratif bekerja. Dalam kasus Spring (dalam contoh saya), deklarasi memiliki lebih banyak baris dan memiliki ekspresi yang sama dengan kode yang sesuai. Jika ada contoh ketika deklarasi tersebut lebih pendek dari kode - Saya ingin melihatnya.

Prinsip Inversion of Control memungkinkan pengujian unit yang mudah karena Anda dapat mengganti implementasi nyata dengan yang palsu (seperti mengganti database SQL dengan database dalam memori)

Saya memahami inversi manfaat kontrol (saya lebih suka menyebut pola desain yang dibahas di sini sebagai Injeksi Ketergantungan, karena IoC lebih umum - ada banyak jenis kontrol, dan kami hanya membalik salah satunya - kontrol inisialisasi). Saya bertanya mengapa seseorang membutuhkan sesuatu selain bahasa pemrograman untuk itu. Saya pasti dapat mengganti implementasi nyata dengan yang palsu menggunakan kode. Dan kode ini akan mengungkapkan hal yang sama dengan konfigurasi - kode ini hanya akan menginisialisasi bidang dengan nilai palsu.

mary = new FakeFemale();

Saya mengerti manfaat DI. Saya tidak mengerti manfaat apa yang ditambahkan oleh konfigurasi XML eksternal dibandingkan dengan kode konfigurasi yang melakukan hal yang sama. Saya tidak berpikir bahwa kompilasi harus dihindari - saya mengkompilasi setiap hari dan saya masih hidup. Saya pikir konfigurasi DI adalah contoh buruk dari pendekatan deklaratif. Deklarasi dapat berguna jika dideklarasikan sekali DAN digunakan berkali-kali dengan cara yang berbeda - seperti hibernate cfg, di mana pemetaan antara properti kacang dan kolom DB digunakan untuk menyimpan, memuat, membuat kueri penelusuran, dll. Konfigurasi Spring DI dapat dengan mudah diterjemahkan ke mengkonfigurasi kode, seperti di awal pertanyaan ini, bukan? Dan itu hanya digunakan untuk inisialisasi kacang, bukan? Yang berarti pendekatan deklaratif tidak menambahkan apapun di sini, bukan?

Ketika saya mendeklarasikan pemetaan hibernasi, saya hanya memberikan beberapa informasi pada hibernasi, dan bekerja berdasarkan itu - saya tidak memberi tahu apa yang harus dilakukan. Dalam kasus musim semi, deklarasi saya memberi tahu musim semi apa yang harus dilakukan - jadi mengapa mendeklarasikannya, mengapa tidak melakukannya saja?


PEMBARUAN TERAKHIR: Teman-teman
, banyak jawaban yang memberi tahu saya tentang injeksi ketergantungan, yang SAYA TAHU BAIK. Pertanyaannya adalah tentang tujuan konfigurasi DI daripada menginisialisasi kode - Saya cenderung berpikir bahwa menginisialisasi kode lebih pendek dan lebih jelas. Satu-satunya jawaban yang saya dapatkan sejauh ini untuk pertanyaan saya, adalah bahwa ia menghindari kompilasi ulang, ketika konfigurasi berubah. Saya kira saya harus memposting pertanyaan lain, karena ini adalah rahasia besar bagi saya, mengapa kompilasi harus dihindari dalam kasus ini.

Pavel Feldman
sumber
21
Akhirnya seseorang memiliki keberanian untuk menanyakan pertanyaan ini. Mengapa memang Anda ingin menghindari kompilasi ulang saat implementasi Anda berubah dengan mengorbankan (atau setidaknya menurunkan) dukungan alat / IDE?
Christian Klauser
3
Sepertinya judulnya kurang tepat. Penulis telah mengatakan bahwa wadah IOC baik-baik saja, tetapi tampaknya bermasalah dengan menggunakan konfigurasi XML daripada mengkonfigurasi melalui kode (dan cukup adil juga). Saya mungkin akan menyarankan "Apa manfaat mengonfigurasi wadah IOC melalui XML atau pendekatan non-kode lainnya?"
Orion Edwards
Contoh @Orion yang saya berikan (dengan Pria dan Wanita) tidak memerlukan wadah IOC. Saya baik-baik saja dengan IOC; menggunakan wadah apakah itu dikonfigurasi menggunakan XML atau tidak, masih menjadi pertanyaan terbuka bagi saya.
Pavel Feldman
@Orion 2: Meskipun saya menggunakan beberapa bentuk IOC di sebagian besar proyek, beberapa di antaranya mendapat manfaat dari penampung IOC sebanyak mereka mendapat manfaat dari Penampung Penugasan Variabel atau Jika Penampung Pernyataan - bahasa saja sudah cukup bagi saya. Saya tidak punya masalah mengkompilasi ulang proyek yang sedang saya kerjakan, dan memiliki kode inisialisasi dev / test / produksi yang dipisahkan dengan mudah. Jadi bagi saya judul tidak masalah.
Pavel Feldman
Saya melihat masalah dengan sampel. Salah satu prinsipnya adalah layanan Injeksi, bukan data
Jacek Cz

Jawaban:

40

Bagi saya sendiri, salah satu alasan utama untuk menggunakan IoC (dan memanfaatkan konfigurasi eksternal) ada di sekitar dua area:

  • Menguji
  • Pemeliharaan produksi

Menguji

Jika Anda membagi pengujian menjadi 3 skenario (yang cukup normal dalam pengembangan skala besar):

  1. Pengujian unit
  2. Tes integrasi
  3. Pengujian kotak hitam

Apa yang ingin Anda lakukan adalah untuk dua skenario pengujian terakhir (Integrasi & kotak Hitam), tidak mengkompilasi ulang bagian mana pun dari aplikasi.

Jika salah satu skenario pengujian Anda mengharuskan Anda untuk mengubah konfigurasi (yaitu: menggunakan komponen lain untuk meniru integrasi perbankan, atau melakukan beban kinerja), ini dapat dengan mudah ditangani (ini memang menguntungkan untuk mengkonfigurasi sisi DI IoC sekalipun.

Selain itu, jika aplikasi Anda digunakan di beberapa situs (dengan konfigurasi server dan komponen yang berbeda) atau memiliki konfigurasi yang berubah di lingkungan langsung, Anda dapat menggunakan tahap pengujian selanjutnya untuk memverifikasi bahwa aplikasi akan menangani perubahan tersebut.

Produksi

Sebagai pengembang, Anda tidak (dan seharusnya tidak) memiliki kendali atas lingkungan produksi (khususnya saat aplikasi Anda didistribusikan ke banyak pelanggan atau situs terpisah), bagi saya ini adalah manfaat nyata menggunakan IoC dan konfigurasi eksternal , karena terserah pada infrastruktur / dukungan produksi untuk mengubah dan menyesuaikan lingkungan hidup tanpa harus kembali ke pengembang dan melalui pengujian (biaya lebih tinggi bila yang mereka ingin lakukan hanyalah memindahkan komponen).

Ringkasan

Manfaat utama konfigurasi eksternal IoC berasal dari memberi orang lain (non-pengembang) kekuatan untuk mengonfigurasi aplikasi Anda, menurut pengalaman saya, ini hanya berguna dalam keadaan tertentu:

  • Aplikasi didistribusikan ke banyak situs / klien di mana lingkungan akan berbeda.
  • Kontrol / masukan pengembangan terbatas atas lingkungan produksi dan pengaturan.
  • Skenario pengujian.

Dalam praktiknya, saya telah menemukan bahwa bahkan ketika mengembangkan sesuatu yang Anda benar-benar memiliki kendali atas lingkungannya, itu akan dijalankan, seiring waktu lebih baik memberi orang lain kemampuan untuk mengubah konfigurasi:

  • Saat mengembangkan Anda tidak tahu kapan itu akan berubah (aplikasi sangat berguna sehingga perusahaan Anda menjualnya kepada orang lain).
  • Saya tidak ingin terjebak dengan mengubah kode setiap kali ada sedikit perubahan yang diminta yang dapat ditangani dengan menyiapkan dan menggunakan model konfigurasi yang baik.

Catatan: Aplikasi mengacu pada solusi lengkap (tidak hanya yang dapat dieksekusi), jadi semua file yang diperlukan untuk menjalankan aplikasi .

Edgar Catalán
sumber
14

Injeksi ketergantungan adalah gaya pengkodean yang berakar pada pengamatan bahwa pendelegasian objek biasanya merupakan pola desain yang lebih berguna daripada pewarisan objek (yaitu, hubungan objek memiliki-lebih berguna daripada objek-hubungan). Namun satu bahan lain diperlukan agar DI bekerja, yaitu membuat antarmuka objek. Menggabungkan dua insinyur perangkat lunak pola desain yang kuat ini dengan cepat menyadari bahwa mereka dapat membuat kode yang digabungkan secara longgar secara fleksibel dan dengan demikian lahirlah konsep Injeksi Ketergantungan. Namun, baru setelah refleksi objek tersedia dalam bahasa tingkat tinggi tertentu DI benar-benar lepas landas. Komponen refleksi adalah inti dari sebagian besar hari ini '

Sebuah bahasa harus memberikan dukungan yang baik untuk kedua teknik pemrograman Berorientasi Objek normal serta dukungan untuk antarmuka objek dan refleksi objek (misalnya Java dan C #). Meskipun Anda dapat membangun program menggunakan pola DI dalam sistem C ++, kurangnya dukungan refleksi dalam bahasa yang tepat mencegahnya dari mendukung server aplikasi dan platform DI lainnya dan karenanya membatasi ekspresi pola DI.

Kekuatan sistem yang dibangun menggunakan pola DI:

  1. Kode DI jauh lebih mudah untuk digunakan kembali karena fungsionalitas 'tergantung' diekstrapolasi menjadi antarmuka yang terdefinisi dengan baik, memungkinkan objek terpisah yang konfigurasinya ditangani oleh platform aplikasi yang sesuai untuk dicolokkan ke objek lain sesuka hati.
  2. Kode DI jauh lebih mudah untuk diuji. Fungsionalitas yang diekspresikan oleh objek dapat diuji dalam kotak hitam dengan membuat objek 'tiruan' yang mengimplementasikan antarmuka yang diharapkan oleh logika aplikasi Anda.
  3. Kode DI lebih fleksibel. Ini adalah kode yang digabungkan secara longgar secara bawaan - yang ekstrim. Hal ini memungkinkan programmer untuk memilih bagaimana objek terhubung secara eksklusif berdasarkan antarmuka yang mereka butuhkan di satu ujung dan antarmuka yang diekspresikan di sisi lain.
  4. Konfigurasi eksternal (Xml) dari objek DI berarti bahwa orang lain dapat menyesuaikan kode Anda ke arah yang tidak terduga.
  5. Konfigurasi eksternal juga merupakan pemisahan pola perhatian di mana semua masalah inisialisasi objek dan manajemen interdependensi objek dapat ditangani oleh server aplikasi.
  6. Perhatikan bahwa konfigurasi eksternal tidak diperlukan untuk menggunakan pola DI, untuk interkoneksi sederhana, objek pembangun kecil seringkali memadai. Ada pertukaran dalam fleksibilitas antara keduanya. Objek pembangun bukanlah opsi yang sefleksibel file konfigurasi yang terlihat secara eksternal. Pengembang sistem DI harus mempertimbangkan keunggulan fleksibilitas daripada kenyamanan, berhati-hati bahwa skala kecil, kontrol butiran halus atas konstruksi objek seperti yang dinyatakan dalam file konfigurasi dapat meningkatkan kebingungan dan biaya pemeliharaan di kemudian hari.

Jelas kode DI tampaknya lebih rumit, kerugian memiliki semua file XML yang mengkonfigurasi objek untuk disuntikkan ke objek lain tampaknya sulit. Namun, inilah inti dari sistem DI. Kemampuan Anda untuk mencampur dan mencocokkan objek kode sebagai rangkaian pengaturan konfigurasi memungkinkan Anda membangun sistem yang kompleks menggunakan kode pihak ketiga dengan sedikit pengkodean di pihak Anda.

Contoh yang diberikan dalam pertanyaan hanya menyentuh permukaan kekuatan ekspresif yang dapat diberikan oleh perpustakaan objek DI dengan faktor yang tepat. Dengan beberapa latihan dan banyak disiplin diri, sebagian besar praktisi DI menemukan bahwa mereka dapat membangun sistem yang memiliki cakupan pengujian 100% dari kode aplikasi. Satu hal ini saja sudah luar biasa. Ini bukan cakupan uji 100% dari aplikasi kecil yang terdiri dari beberapa ratus baris kode, tetapi cakupan uji 100% dari aplikasi yang terdiri dari ratusan ribu baris kode. Saya tidak dapat menjelaskan pola desain lain yang memberikan tingkat kemampuan untuk diuji ini.

Anda benar karena aplikasi yang hanya terdiri dari 10 baris kode lebih mudah dipahami daripada beberapa objek ditambah serangkaian file konfigurasi XML. Namun seperti pola desain yang paling kuat, keuntungan ditemukan saat Anda terus menambahkan fitur baru ke sistem.

Singkatnya, aplikasi berbasis DI skala besar lebih mudah untuk di-debug dan lebih mudah dipahami. Meskipun konfigurasi Xml tidak 'waktu kompilasi dicentang', semua layanan aplikasi yang diketahui oleh penulis ini akan memberikan pesan kesalahan kepada pengembang jika mereka mencoba untuk memasukkan objek yang memiliki antarmuka yang tidak kompatibel ke objek lain. Dan sebagian besar menyediakan fitur 'periksa' yang mencakup semua konfigurasi objek yang diketahui. Ini mudah dan cepat dilakukan dengan memeriksa bahwa objek yang akan diinjeksi A mengimplementasikan antarmuka yang dibutuhkan oleh objek B untuk semua injeksi objek yang dikonfigurasi.

Kevin S.
sumber
4
memahami manfaat DI. Saya tidak mengerti manfaat apa yang ditambahkan oleh konfigurasi XML eksternal dibandingkan dengan kode konfigurasi yang melakukan hal yang sama. Manfaat yang Anda sebutkan disediakan oleh pola desain DI. Pertanyaannya adalah tentang manfaat konfigurasi DI dibandingkan dengan kode inisialisasi biasa.
Pavel Feldman
> Konfigurasi eksternal juga merupakan pemisahan ... Pemisahan konfigurasi merupakan jantung DI yang baik. Dan itu bisa de dome menggunakan kode inisialisasi. Apa yang ditambahkan cfg dibandingkan dengan menginisialisasi kode? Bagi saya tampaknya setiap baris cfg memiliki baris kode inisialisasi yang sesuai.
Pavel Feldman
7

Ini sedikit pertanyaan yang dimuat, tetapi saya cenderung setuju bahwa konfigurasi xml dalam jumlah besar tidak terlalu bermanfaat. Saya suka aplikasi saya dibuat seringan mungkin dengan dependensi, termasuk kerangka kerja yang besar dan kuat.

Mereka sering menyederhanakan kode, tetapi mereka juga memiliki overhead dalam kompleksitas yang membuat pelacakan masalah agak sulit (saya telah melihat masalah seperti itu secara langsung, dan Java langsung saya akan jauh lebih nyaman menangani).

Saya kira itu sedikit tergantung pada gaya, dan apa yang membuat Anda nyaman ... apakah Anda suka menerbangkan solusi Anda sendiri dan mendapat manfaat dari mengetahuinya secara mendalam, atau mengandalkan solusi yang ada yang mungkin terbukti sulit ketika konfigurasinya tidak berjalan ' t tepat? Itu semua pengorbanan.

Namun, konfigurasi XML sedikit menjengkelkan saya ... Saya mencoba menghindarinya dengan cara apa pun.

Mike Stone
sumber
5

Kapan pun Anda dapat mengubah kode Anda menjadi data, Anda membuat langkah ke arah yang benar.

Mengkodekan apa pun sebagai data berarti bahwa kode Anda sendiri lebih umum dan dapat digunakan kembali. Ini juga berarti bahwa data Anda dapat ditentukan dalam bahasa yang benar-benar cocok.

Selain itu, file XML dapat dibaca menjadi GUI atau alat lain dan dengan mudah dimanipulasi secara pragmatis. Bagaimana Anda melakukannya dengan contoh kode?

Saya terus-menerus memfaktorkan hal-hal yang akan diterapkan kebanyakan orang sebagai kode ke dalam data, itu membuat kode yang JAUH lebih bersih. Saya merasa tidak terbayangkan bahwa orang akan membuat menu dalam kode daripada sebagai data - jelas bahwa melakukannya dalam kode jelas salah karena boilerplate.

Bill K.
sumber
masuk akal, tidak memikirkannya dalam perspektif ini
Pavel Feldman
7
sekali lagi, orang sering pergi ke arah lain dan mencoba memasukkan logika ke dalam data yang berarti Anda akhirnya mengkodekan aplikasi Anda dalam bahasa pemrograman di bawah standar
Casebash
@Casebash Itu sudut pandang yang menarik - Saya akan sangat tertarik dengan contoh. Saya menemukan bahwa apa pun yang dapat saya pindahkan ke data membantu. Saya juga menemukan bahwa jika saya melakukan apa yang Anda katakan, bahasanya benar-benar ditingkatkan karena ini adalah DSL - tetapi bahkan dibutuhkan pembenaran yang serius untuk membuat bahasa yang sama sekali baru.
Bill K
1
"Setiap kali Anda dapat mengubah kode Anda menjadi data, Anda membuat langkah ke arah yang benar." Selamat datang di anti-pola Soft Coding.
Raedwald
@Raedwald Yang Anda bicarakan adalah eksternalisasi yang bisa sangat sulit jika Anda tidak tahu apa yang Anda lakukan (dan alasan seseorang yang tidak kompeten mencobanya, gagal dan menyebutnya sebagai anti-pola) Contoh yang lebih positif adalah Injeksi, Iterator , hampir semua hal dengan anotasi, apa pun yang diinisialisasi dengan array. Sebagian besar struktur pemrograman yang hebat adalah upaya untuk memisahkan perbedaan dalam kode Anda dan menggabungkan apa yang tersisa, mendorongnya dengan sesuatu yang dapat dikelompokkan dan dikelola dengan lebih baik.
Bill K
3

Alasan menggunakan kontainer DI adalah karena Anda tidak harus memiliki satu miliar properti yang telah dikonfigurasi sebelumnya dalam kode Anda yang hanya berupa getter dan setter. Apakah Anda benar-benar ingin melakukan hardcode semua dengan X baru ()? Tentu, Anda dapat memiliki default, tetapi wadah DI memungkinkan pembuatan lajang yang sangat mudah dan memungkinkan Anda untuk fokus pada detail kode, bukan tugas lain-lain untuk memulainya.

Misalnya, Spring memungkinkan Anda mengimplementasikan antarmuka InitializingBean dan menambahkan metode afterPropertiesSet (Anda juga dapat menentukan "metode-init" untuk menghindari penggandengan kode Anda ke Spring). Metode ini akan memungkinkan Anda untuk memastikan bahwa setiap antarmuka yang ditentukan sebagai bidang dalam instance kelas Anda dikonfigurasi dengan benar saat startup, dan kemudian Anda tidak lagi harus mengecek getter dan setter Anda secara null (dengan asumsi Anda mengizinkan lajang Anda tetap aman untuk thread ).

Lebih jauh lagi, jauh lebih mudah untuk melakukan inisialisasi kompleks dengan wadah DI daripada melakukannya sendiri. Misalnya, saya membantu menggunakan XFire (bukan CeltiXFire, kami hanya menggunakan Java 1.4). Aplikasi ini menggunakan Spring, tetapi sayangnya menggunakan mekanisme konfigurasi services.xml XFire. Ketika Kumpulan elemen diperlukan untuk menyatakan bahwa ia memiliki NOL atau lebih banyak contoh daripada SATU atau lebih contoh, saya harus mengganti beberapa kode XFire yang disediakan untuk layanan khusus ini.

Ada default XFire tertentu yang ditentukan dalam skema kacang Spring-nya. Jadi, jika kami menggunakan Spring untuk mengonfigurasi layanan, kacang mungkin sudah digunakan. Alih-alih, yang terjadi adalah saya harus menyediakan instance kelas tertentu di file services.xml alih-alih menggunakan kacang. Untuk melakukan ini, saya perlu menyediakan konstruktor dan menyiapkan referensi yang dideklarasikan dalam konfigurasi XFire. Perubahan nyata yang perlu saya lakukan mengharuskan saya membebani satu kelas.

Namun, berkat file services.xml, saya harus membuat empat kelas baru, menyetel defaultnya sesuai dengan defaultnya di file konfigurasi Spring di konstruktornya. Jika kami dapat menggunakan konfigurasi Spring, saya bisa saja menyatakan:

<bean id="base" parent="RootXFireBean">
    <property name="secondProperty" ref="secondBean" />
</bean>

<bean id="secondBean" parent="secondaryXFireBean">
    <property name="firstProperty" ref="thirdBean" />
</bean>

<bean id="thirdBean" parent="thirdXFireBean">
    <property name="secondProperty" ref="myNewBean" />
</bean>

<bean id="myNewBean" class="WowItsActuallyTheCodeThatChanged" />

Sebaliknya, lebih terlihat seperti ini:

public class TheFirstPointlessClass extends SomeXFireClass {
    public TheFirstPointlessClass() {
        setFirstProperty(new TheSecondPointlessClass());
        setSecondProperty(new TheThingThatWasHereBefore());
    }
}

public class TheSecondPointlessClass extends YetAnotherXFireClass {
    public TheSecondPointlessClass() {
        setFirstProperty(TheThirdPointlessClass());
    }
}

public class TheThirdPointlessClass extends GeeAnotherXFireClass {
    public TheThirdPointlessClass() {
        setFirstProperty(new AnotherThingThatWasHereBefore());
        setSecondProperty(new WowItsActuallyTheCodeThatChanged());
    }
}

public class WowItsActuallyTheCodeThatChanged extends TheXFireClassIActuallyCareAbout {
    public WowItsActuallyTheCodeThatChanged() {
    }

    public overrideTheMethod(Object[] arguments) {
        //Do overridden stuff
    }
}

Jadi hasil akhirnya adalah empat kelas Java tambahan yang sebagian besar tidak berguna harus ditambahkan ke basis kode untuk mencapai pengaruh satu kelas tambahan dan beberapa informasi wadah ketergantungan sederhana yang dicapai. Ini bukan "pengecualian yang membuktikan aturan", ini IS aturannya ... menangani quirks dalam kode jauh lebih bersih ketika properti sudah disediakan dalam wadah DI dan Anda hanya mengubahnya agar sesuai dengan situasi khusus, yang terjadi lebih sering daripada tidak.

MetroidFan2002
sumber
3

Saya punya jawaban Anda

Jelas ada trade off dalam setiap pendekatan, tetapi file konfigurasi XML yang dieksternalisasi berguna untuk pengembangan perusahaan di mana sistem build digunakan untuk mengompilasi kode dan bukan IDE Anda. Dengan menggunakan sistem build, Anda mungkin ingin memasukkan nilai-nilai tertentu ke dalam kode Anda - misalnya versi build (yang mungkin sulit untuk diupdate secara manual setiap kali Anda mengompilasi). Rasa sakitnya lebih besar saat sistem build Anda menarik kode dari beberapa sistem kontrol versi. Memodifikasi nilai sederhana pada waktu kompilasi akan mengharuskan Anda mengubah file, mengikatnya, mengkompilasi, dan kemudian mengembalikannya setiap kali untuk setiap perubahan. Ini bukanlah perubahan yang ingin Anda lakukan ke kontrol versi Anda.

Kasus penggunaan berguna lainnya terkait sistem build dan konfigurasi eksternal:

  • menyuntikkan gaya / lembar gaya untuk satu basis kode untuk berbagai build
  • memasukkan kumpulan konten dinamis yang berbeda (atau referensi ke dalamnya) untuk basis kode tunggal Anda
  • menyuntikkan konteks pelokalan untuk berbagai build / klien
  • mengubah URI webservice ke server cadangan (saat yang utama mati)

Pembaruan: Semua contoh di atas adalah pada hal-hal yang tidak memerlukan ketergantungan pada kelas. Tetapi Anda dapat dengan mudah membuat kasus ketika objek kompleks dan otomatisasi diperlukan - misalnya:

  • Bayangkan Anda memiliki sistem yang memantau lalu lintas situs web Anda. Bergantung pada # pengguna serentak, mekanisme logging on / off. Mungkin saat mekanismenya mati, objek rintisan diletakkan di tempatnya.
  • Bayangkan Anda memiliki sistem konferensi web di mana bergantung pada # pengguna, Anda ingin mengalihkan kemampuan melakukan P2P tergantung pada # peserta
badunk
sumber
+1 untuk menyoroti aspek perusahaan tepat di atas. Menguji kode warisan yang ditulis dengan buruk terkadang bisa menjadi mimpi buruk selama berhari-hari.
Richard Le Mesurier
2

Anda tidak perlu mengkompilasi ulang kode Anda setiap kali Anda mengubah sesuatu dalam konfigurasi. Ini akan menyederhanakan penyebaran dan pemeliharaan program. Misalnya Anda dapat menukar satu komponen dengan yang lain hanya dengan 1 perubahan pada file konfigurasi.

aku
sumber
penyebaran? mungkin ... pemeliharaan penerapan? mungkin ... pemeliharaan kode? Saya cenderung berpikir tidak ... debugging melalui kerangka kerja cenderung menjadi sakit kepala besar, dan pojos jauh lebih mudah ditangani dalam hal itu.
Mike Stone
1
Mike, saya tidak mengatakan apa-apa tentang kode. Kita semua tahu bahwa konfigurasi XML menyebalkan :)
aku
Hmm .. seberapa sering Anda mengganti komponen tanpa kompilasi ulang dan untuk apa? Saya mengerti jika seseorang mengubah kredensial DB dan tidak ingin mengkompilasi ulang program - dia mungkin bukan orang yang mengembangkannya. Tapi saya hampir tidak bisa membayangkan seseorang selain pengembang mengubah konfigurasi pegas
Pavel Feldman
Biasanya Pavel situasi ini terjadi ketika Anda harus menyebarkan program ke ratusan klien. Dalam situasi seperti itu, jauh lebih mudah untuk mengubah konfigurasi daripada menerapkan versi baru produk. Anda benar mengatakan tentang devs. Biasanya pengembang membuat cfg baru dan admin menerapkannya.
aku
2

Anda dapat memasukkan implementasi baru untuk pacar. Jadi wanita baru dapat disuntikkan tanpa mengkompilasi ulang kode Anda.

<bean id="jane" class="foo.bar.HotFemale">
  <property name="age" value="19"/>
</bean>
<bean id="mary" class="foo.bar.Female">
  <property name="age" value="23"/>
</bean>
<bean id="john" class="foo.bar.Male">
  <property name="girlfriend" ref="jane"/>
</bean>

(Di atas mengasumsikan Female dan HotFemale menerapkan antarmuka GirlfFriend yang sama)

Paul Whelan
sumber
Mengapa modifikasi logika tanpa kompilasi ulang dianggap sebagai ide yang bagus?
Pavel Feldman
Saya pasti bisa melakukan HotFemale jane = new HotFmale (); jane.setAge (19); john.setGirlfriend (jane); Jadi satu-satunya perbedaan adalah cfg dapat diubah tanpa kompilasi ulang? Sepertinya itu jawaban yang umum ketika Spring dibahas. Mengapa?! Mengapa baik untuk menghindari kompilasi?
Pavel Feldman
Yah saya bisa menguji kode lebih baik saya bisa Mock the Female Object.
Paul Whelan
@Pavel Feldman: karena jika Anda sudah memiliki aplikasi yang diterapkan di klien, ini lebih mudah.
Andrei Rînea
1

Di dunia .NET, sebagian besar kerangka kerja IoC menyediakan konfigurasi XML dan Kode.

StructureMap dan Ninject, misalnya, menggunakan antarmuka yang lancar untuk mengonfigurasi container. Anda tidak lagi dibatasi untuk menggunakan file konfigurasi XML. Spring, yang juga ada di .NET, sangat bergantung pada file XML karena ini adalah antarmuka konfigurasi utama historisnya, tetapi masih mungkin untuk mengonfigurasi container secara terprogram.

Romain Verdier
sumber
Bagus sekali akhirnya saya bisa menggunakan kode untuk apa yang dimaksudkan untuk digunakan :) Tapi mengapa saya bahkan memerlukan sesuatu selain bahasa pemrograman untuk melakukan hal-hal seperti itu?
Pavel Feldman
Saya pikir itu karena XML memungkinkan perubahan runtime, atau setidaknya, perubahan konfigurasi tanpa harus mengkompilasi ulang proyek.
Romain Verdier
1

Kemudahan dalam menggabungkan konfigurasi parsial menjadi konfigurasi lengkap akhir.

Misalnya, dalam aplikasi web, model, tampilan, dan pengontrol biasanya ditentukan dalam file konfigurasi terpisah. Gunakan pendekatan deklaratif, Anda dapat memuat, misalnya:

  UI-context.xml
  Model-context.xml
  Controller-context.xml

Atau muat dengan UI berbeda dan beberapa pengontrol tambahan:

  AlternateUI-context.xml
  Model-context.xml
  Controller-context.xml
  ControllerAdditions-context.xml

Untuk melakukan hal yang sama dalam kode memerlukan infrastruktur untuk menggabungkan konfigurasi parsial. Bukan tidak mungkin dilakukan dalam kode, tetapi yang pasti lebih mudah dilakukan menggunakan framework IoC.

mengentalkan
sumber
1

Seringkali, poin penting adalah siapa yang mengubah konfigurasi setelah program ditulis. Dengan konfigurasi dalam kode, Anda secara implisit berasumsi bahwa orang yang mengubahnya memiliki keahlian dan akses yang sama ke kode sumber, dll seperti yang dimiliki oleh pembuat aslinya.

Dalam sistem produksi, sangat praktis untuk mengekstrak beberapa subset pengaturan (misalnya usia dalam Anda misalnya) ke file XML dan memungkinkan misalnya administrator sistem atau dukungan pribadi untuk mengubah nilai tanpa memberi mereka kekuatan penuh atas kode sumber atau pengaturan lain - atau hanya untuk mengisolasi mereka dari kerumitan.

Miro A.
sumber
Itu poin yang valid, tetapi konfigurasi pegas seringkali cenderung agak rumit. Meskipun mudah untuk mengubah usia, sysadmin masih harus berurusan dengan file xml besar yang tidak perlu dia pahami sepenuhnya. Bukankah lebih baik mengekstrak bagian yang seharusnya dikonfigurasi menjadi sesuatu yang lebih sederhana, daripada konfigurasi XML musim semi? Seperti file properti, dengan satu baris "age = 23" dan tidak mengizinkan admin mengubah detail lain, seperti nama kelas, dll, yang memerlukan pengetahuan tentang struktur program internal.
Pavel Feldman
Saya baru-baru ini mengerjakan proyek yang memiliki campuran kode Java dan XSLT. Timnya adalah campuran orang-orang yang kuat di Java (dan mungkin kurang nyaman bekerja dengan XML dan XSLT); dan orang-orang yang sangat kuat bekerja dengan XML dan XSLT (dan kurang nyaman dengan Java). Karena konfigurasi akan dikelola oleh grup kedua, masuk akal untuk menggunakan Spring, dan memiliki konfigurasi XML. Dengan kata lain, Spring memecahkan masalah pembagian kerja dalam tim. Itu tidak memecahkan masalah "teknis"; dalam arti bahwa konfigurasi dapat dengan mudah dilakukan dengan kode Java.
Dawood ibn Kareem
Kapan 'personel pendukung' tahu tentang keharusan mengubah beberapa kelas yang dibuat dalam wadah injeksi ketergantungan ?? Benar-benar dengan asumsi bahwa itu tugas pengembang untuk melakukan ini?
Jimbo
Itulah alasan mengapa mengekstrak nilai konfigurasi (misalnya URL sistem yang Anda integrasikan dengan) masuk akal: file properti pengeditan personel pendukung atau (dalam kasus terburuk) file XML, kelas Java yang dikompilasi tetap sama.
Miro A.
1

Dari perspektif Musim Semi, saya dapat memberi Anda dua jawaban.

Pertama, konfigurasi XML bukanlah satu-satunya cara untuk menentukan konfigurasi. Kebanyakan hal dapat dikonfigurasi menggunakan anotasi dan hal-hal yang harus dilakukan dengan XML adalah konfigurasi untuk kode yang tidak Anda tulis, seperti kumpulan koneksi yang Anda gunakan dari perpustakaan. Spring 3 menyertakan metode untuk mendefinisikan konfigurasi DI menggunakan Java yang mirip dengan konfigurasi DI hand rolled dalam contoh Anda. Jadi menggunakan Spring tidak berarti Anda harus menggunakan file konfigurasi berbasis XML.

Kedua Spring jauh lebih dari sekedar kerangka DI. Ini memiliki banyak fitur lain termasuk manajemen transaksi dan AOP. Konfigurasi Spring XML menggabungkan semua konsep ini. Seringkali dalam file konfigurasi yang sama saya menentukan dependensi kacang, pengaturan transaksi, dan menambahkan kacang cakupan sesi yang benar-benar ditangani menggunakan AOP di latar belakang. Saya menemukan konfigurasi XML menyediakan tempat yang lebih baik untuk mengelola semua fitur ini. Saya juga merasa bahwa konfigurasi berbasis anotasi dan konfigurasi XML ditingkatkan lebih baik daripada melakukan konfigurasi berbasis Java.

Tapi saya mengerti maksud Anda dan tidak ada yang salah dengan mendefinisikan konfigurasi injeksi ketergantungan di Java. Saya biasanya melakukannya sendiri dalam pengujian unit dan ketika saya mengerjakan proyek yang cukup kecil sehingga saya belum menambahkan kerangka DI. Saya biasanya tidak menentukan konfigurasi di Java karena bagi saya itu adalah jenis kode pipa yang saya coba hindari dari penulisan ketika saya memilih untuk menggunakan Spring. Itu adalah preferensi meskipun, itu tidak berarti bahwa konfigurasi XML lebih unggul dari konfigurasi berbasis Java.

David W Crook
sumber
0

Spring juga memiliki loader properti. Kami menggunakan metode ini untuk mengatur variabel yang bergantung pada lingkungan (misalnya pengembangan, pengujian, penerimaan, produksi, ...). Ini bisa menjadi contoh antrian untuk didengarkan.

Jika tidak ada alasan mengapa properti berubah, tidak ada alasan untuk mengonfigurasinya dengan cara ini.

Jeroen Wyseur
sumber
0

Kasing Anda sangat sederhana dan oleh karena itu tidak memerlukan wadah IoC (Inversion of Control) seperti Spring. Di sisi lain, ketika Anda "memprogram ke antarmuka, bukan implementasi" (yang merupakan praktik yang baik di OOP), Anda dapat memiliki kode seperti ini:

IService myService;
// ...
public void doSomething() {
  myService.fetchData();
}

(perhatikan bahwa jenis myService adalah IService - antarmuka, bukan implementasi konkret). Sekarang akan berguna untuk membiarkan penampung IoC Anda secara otomatis menyediakan contoh konkret IService yang benar selama inisialisasi - ketika Anda memiliki banyak antarmuka dan banyak implementasi, mungkin sulit untuk melakukannya secara manual. Manfaat utama wadah IoC (kerangka kerja injeksi ketergantungan) adalah:

  • Konfigurasi eksternal pemetaan antara antarmuka dan implementasi konkretnya
  • Wadah IoC menangani beberapa masalah rumit seperti menyelesaikan grafik ketergantungan yang rumit, mengelola masa pakai komponen, dll.
  • Anda menghemat waktu pengkodean karena Anda memberikan pemetaan secara deklaratif, bukan dalam kode prosedural
  • Prinsip Inversion of Control memungkinkan pengujian unit yang mudah karena Anda dapat mengganti implementasi nyata dengan yang palsu (seperti mengganti database SQL dengan database dalam memori)
Borek Bernard
sumber
0

Menginisialisasi dalam file konfigurasi XML akan menyederhanakan pekerjaan debugging / adaptasi Anda dengan klien yang telah menerapkan aplikasi Anda di komputer mereka. (Karena tidak memerlukan kompilasi ulang + penggantian file biner)

Andrei Rînea
sumber
-2

Salah satu alasan paling menarik adalah " Prinsip Hollywood ": jangan hubungi kami, kami akan menghubungi Anda. Sebuah komponen tidak diperlukan untuk melakukan pencarian ke komponen dan layanan itu sendiri; sebaliknya mereka diberikan secara otomatis. Di Java, ini berarti tidak perlu lagi melakukan pencarian JNDI di dalam komponen.

Juga jauh lebih mudah untuk menguji unit komponen secara terpisah: daripada memberikan implementasi aktual dari komponen yang dibutuhkannya, Anda cukup menggunakan (mungkin dibuat secara otomatis) tiruan.

jan.vdbergh
sumber
Jawaban ini tentang injeksi ketergantungan. Saya tahu apa itu, saya tahu itu bagus dan saya nyatakan dengan jelas di kalimat pertama pertanyaan. Pertanyaannya adalah tentang manfaat konfigurasi DI, dibandingkan dengan kode inisialisasi biasa.
Pavel Feldman
Tidak benar-benar menjawab pertanyaan
Casebash