Bağımlılık enjeksiyon konteynerlerinin faydaları nelerdir?


104

Bağımlılık enjeksiyonunun faydalarını anlıyorum. Mesela Baharı ele alalım. Ayrıca AOP, farklı türden yardımcılar gibi diğer Spring özelliklerinin faydalarını da anlıyorum. XML yapılandırmasının aşağıdaki gibi faydalarının neler olduğunu merak ediyorum:

<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>

düz eski java koduyla karşılaştırıldığında, örneğin:

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

bu daha kolay hata ayıklama, derleme zamanı kontrol etme ve yalnızca java bilen herkes tarafından anlaşılabilir. Öyleyse bir bağımlılık enjeksiyon çerçevesinin temel amacı nedir? (veya faydalarını gösteren bir kod parçası.)


GÜNCELLEME:
Durumunda

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

Birden fazla varsa, IoC çerçevesi myService'in hangi uygulamasının enjekte edilmesini istediğimi nasıl tahmin edebilir? Verilen arayüzün yalnızca bir uygulaması varsa ve IoC konteynerinin onu kullanmaya otomatik olarak karar vermesine izin verirsem, ikinci bir uygulama göründükten sonra kırılacaktır. Ve bir arayüzün kasıtlı olarak yalnızca bir olası uygulaması varsa, onu enjekte etmenize gerek yoktur.

IoC'nin faydalarını gösteren küçük bir yapılandırma parçası görmek gerçekten ilginç olurdu. Spring'i bir süredir kullanıyorum ve böyle bir örnek veremem. Ve hazırda bekletme, dwr ve kullandığım diğer çerçevelerin faydalarını gösteren tek satırlar gösterebilirim.


GÜNCELLEME 2:
IoC yapılandırmasının yeniden derlenmeden değiştirilebileceğinin farkındayım. Gerçekten o kadar iyi bir fikir mi? Birisi yeniden derlemeden DB kimlik bilgilerini değiştirmek istediğinde anlayabiliyorum - geliştirici olmayabilir. Uygulamanızda, geliştiriciden başka biri IoC yapılandırmasını ne sıklıkla değiştiriyor? Geliştiriciler için yapılandırmayı değiştirmek yerine belirli bir sınıfı yeniden derleme çabası olmadığını düşünüyorum. Ve geliştirici olmayanlar için muhtemelen hayatını kolaylaştırmak ve daha basit bir yapılandırma dosyası sağlamak istersiniz.


GÜNCELLEME 3:

Arayüzler ve somut uygulamaları arasında haritalamanın harici konfigürasyonu

Onu dıştan yapmakta bu kadar iyi olan nedir? Kodunuzun tamamını harici yapmazsınız, ancak kesinlikle - ClassName.java.txt dosyasına yerleştirin, anında manuel olarak okuyun ve derleyin - vay, yeniden derlemekten kaçındınız. Derlemeden neden kaçınılmalı ?!

Eşlemeleri prosedürel kodda değil, bildirimli olarak sağladığınız için kodlama süresinden tasarruf edersiniz

Bazen bildirimsel yaklaşımın zaman kazandırdığını anlıyorum. Örneğin, bir bean özelliği ile bir DB sütunu arasındaki bir eşlemenin yalnızca bir kez beyan ederim ve hazırda bekletme bu eşlemeyi HSQL'e dayalı olarak SQL oluştururken, kaydederken, kullanır. Bu, bildirimsel yaklaşımın çalıştığı yerdir. Bahar durumunda (benim örneğimde), beyan daha fazla satıra sahipti ve karşılık gelen kodla aynı ifadeye sahipti. Böyle bir beyanın koddan daha kısa olduğu bir örnek varsa - onu görmek isterim.

Kontrolü Ters Çevirme ilkesi, gerçek uygulamaları sahte olanlarla değiştirebileceğiniz için kolay birim testine izin verir (SQL veritabanını bellek içi biriyle değiştirmek gibi)

Kontrol faydalarının tersine çevrilmesini anlıyorum (Burada tartışılan tasarım modelini Bağımlılık Enjeksiyonu olarak adlandırmayı tercih ediyorum, çünkü IoC daha geneldir - birçok kontrol türü vardır ve biz sadece birini tersine çeviriyoruz - başlatma kontrolü). Neden birinin bunun için bir programlama dilinden başka bir şeye ihtiyacı olduğunu soruyordum. Gerçek uygulamaları kesinlikle kod kullanarak sahte olanlarla değiştirebilirim. Ve bu kod, konfigürasyonla aynı şeyi ifade edecek - alanları sahte değerlerle başlatacak.

mary = new FakeFemale();

DI'nin faydalarını anlıyorum. Aynı şeyi yapan kodu yapılandırmaya kıyasla harici XML yapılandırmasının hangi faydaları eklediğini anlamıyorum. Derlemeden kaçınılması gerektiğini düşünmüyorum - her gün derliyorum ve hala hayattayım. DI yapılandırmasının bildirimsel yaklaşımın kötü bir örneği olduğunu düşünüyorum. Bildirim, bir kez bildirilirse VE farklı şekillerde birçok kez kullanılırsa yararlı olabilir - örneğin, bean özelliği ile DB sütunu arasındaki eşlemenin, kaydetme, yükleme, arama sorguları oluşturma vb. İçin kullanıldığı hazırda bekletme cfg gibi. Spring DI yapılandırması, kolayca tercüme edilebilir Bu sorunun başında olduğu gibi kod yapılandırmak, değil mi? Ve sadece fasulye başlatmak için kullanılıyor, değil mi? Bu, bildirimsel yaklaşımın buraya hiçbir şey eklemediği anlamına gelir, değil mi?

Hazırda bekletme eşleştirmesini ilan ettiğimde, sadece bazı bilgileri hazırda bekletme moduna alıyorum ve buna göre çalışıyor - ne yapacağımı söylemiyorum. İlkbahar durumunda, beyanım ilkbahara tam olarak ne yapması gerektiğini söylüyor - öyleyse neden ilan etsin, neden sadece yapmayasın?


SON GÜNCELLEME:
Beyler, birçok cevap bana iyi olduğunu bildiğim bağımlılık enjeksiyonu hakkında konuşuyor. Soru, kodu başlatmak yerine DI konfigürasyonunun amacı ile ilgilidir - kodu başlatmanın daha kısa ve daha net olduğunu düşünüyorum. Soruma şu ana kadar aldığım tek cevap, konfigürasyon değiştiğinde yeniden derlemeyi engellemesi. Sanırım bir soru daha yazmalıyım, çünkü bu benim için büyük bir sır, bu durumda neden derlemeden kaçınılmalı.


21
Sonunda birisi bu soruyu sormaya cesaret etti. Araç / IDE desteğinden ödün vermek (veya en azından küçültmek) pahasına uygulamanız değiştiğinde neden yeniden derlemeden kaçınmak istiyorsunuz?
Christian Klauser

3
Görünüşe göre başlık pek doğru değil. Yazar, IOC kapsayıcılarının iyi olduğunu söyledi, ancak kod aracılığıyla yapılandırmak yerine (ve yeterince adil) XML yapılandırması kullanmakla sorun yaşıyor gibi görünüyor. Belki de "IOC kapsayıcılarını XML veya diğer kod dışı yaklaşımlarla yapılandırmanın faydaları nelerdir?"
Orion Edwards

Sağladığım @ Orion Örnekleri (Erkek ve Kadın ile) herhangi bir IOC kapsayıcısı gerektirmiyor. IOC ile iyiyim; XML kullanılarak yapılandırılmış olsun ya da olmasın konteyner kullanmak benim için hala açık bir sorudur.
Pavel Feldman

@Orion 2: Projelerin çoğunda bir çeşit IOC kullansam da, bazıları Variable Assignment Container veya If Statement Container'dan yararlandıkları kadar IOC kapsayıcısından da yararlanıyor - çoğu zaman benim için sadece dil yeterli. Üzerinde çalıştığım projeleri yeniden derlerken sorun yaşamıyorum ve geliştirici / test / üretim başlatan kodu uygun şekilde ayrılmış. Yani benim için başlık iyidir.
Pavel Feldman

Örnekte sorun görüyorum. Veri değil
Jacek Cz

Yanıtlar:


40

Benim için bir IoC kullanmanın (ve harici konfigürasyondan yararlanmanın) ana nedenlerinden biri şu iki alanla ilgilidir:

  • Test yapmak
  • Üretim bakımı

Test yapmak

Testinizi 3 senaryoya ayırırsanız (büyük ölçekli geliştirmede oldukça normaldir):

  1. Birim testi
  2. Entegrasyon testi
  3. Kara kutu testi

Yapmak isteyeceğiniz şey, son iki test senaryosu için (Entegrasyon ve Kara kutu), uygulamanın herhangi bir bölümünü yeniden derlememek.

Test senaryolarınızdan herhangi biri yapılandırmayı değiştirmenizi gerektiriyorsa (yani: bir bankacılık entegrasyonunu taklit etmek için başka bir bileşen kullanın veya bir performans yükü yapın), bu kolayca halledilebilir (bu, bir IoC olsa da.

Ek olarak, uygulamanız birden fazla sitede kullanılıyorsa (farklı sunucu ve bileşen yapılandırmasıyla) veya canlı ortamda değişen bir yapılandırmaya sahipse, uygulamanın bu değişiklikleri işleyeceğini doğrulamak için testin sonraki aşamalarını kullanabilirsiniz.

Üretim

Bir geliştirici olarak üretim ortamının kontrolüne sahip değilsiniz (ve olmamalısınız) (özellikle uygulamanız birden fazla müşteriye veya ayrı siteye dağıtıldığında), bu benim için hem IoC hem de harici konfigürasyon kullanmanın gerçek avantajıdır. , geliştiricilere geri dönmek zorunda kalmadan ve test yoluyla canlı ortamı ayarlamak ve ayarlamak altyapı / üretim desteğine bağlı olduğundan (tek yapmak istedikleri bir bileşeni taşımak olduğunda daha yüksek maliyet).

Özet

Bir IoC'nin harici yapılandırmasının temel faydaları, başkalarına (geliştirici olmayanlara) uygulamanızı yapılandırma gücü vermekten gelir; deneyimlerime göre bu, yalnızca sınırlı bir koşulda yararlıdır:

  • Uygulama, ortamların farklı olacağı birden çok siteye / istemciye dağıtılmıştır.
  • Üretim ortamı ve kurulum üzerinde sınırlı geliştirme kontrolü / girdisi.
  • Test senaryoları.

Uygulamada, ortam üzerinde kontrolünüzün olduğu bir şeyi geliştirirken bile çalıştırılacağını, zamanla bir başkasına yapılandırmayı değiştirme yetenekleri vermenin daha iyi olduğunu buldum:

  • Geliştirme sırasında ne zaman değişeceğini bilemezsiniz (uygulama o kadar yararlıdır ki şirketiniz onu başka birine satar).
  • İyi bir konfigürasyon modeli kurarak ve kullanarak halledilebilecek küçük bir değişiklik istendiğinde her seferinde kodu değiştirmeye takılıp kalmak istemiyorum.

Not: Uygulama tam çözümü ifade eder (sadece yürütülebilir değil), bu nedenle uygulamanın çalışması için gereken tüm dosyalar .


14

Bağımlılık ekleme, köklerini nesne yetkilendirmesinin genellikle nesne kalıtımından daha kullanışlı bir tasarım modeli olduğu gözlemine dayanan bir kodlama stilidir (yani, nesnenin-bir ilişkisi nesne-bir ilişkiden daha yararlıdır). Bununla birlikte, DI'nın çalışması için, nesne arayüzleri oluşturmak için başka bir bileşen gereklidir. Bu iki güçlü tasarım modelini birleştiren yazılım mühendisleri, esnek gevşek bağlı kod oluşturabileceklerini çabucak fark ettiler ve böylece Bağımlılık Enjeksiyonu kavramı doğdu. Ancak, DI'nın gerçekten yükseldiği bazı yüksek seviyeli dillerde nesne yansıması mevcut hale gelene kadar değildi. Yansıma bileşeni, günümüzün çoğunun özüdür '

Bir dil, hem normal Nesne Yönelimli programlama teknikleri için hem de nesne arayüzleri ve nesne yansıması için destek sağlamalıdır (örneğin Java ve C #). C ++ sistemlerinde DI kalıplarını kullanarak programlar oluşturabilseniz de, uygun dilde yansıtma desteğinin olmaması, uygulama sunucularını ve diğer DI platformlarını desteklemesini engeller ve dolayısıyla DI kalıplarının ifadesini sınırlar.

DI kalıpları kullanılarak oluşturulmuş bir sistemin güçlü yönleri:

  1. Yapılandırması uygun bir uygulama platformu tarafından işlenen ayrı nesnelerin isteğe bağlı olarak diğer nesnelere takılmasına izin vererek, 'bağlı' işlevsellik iyi tanımlanmış arayüzlere ekstrapole edildiğinden, DI kodunun yeniden kullanımı çok daha kolaydır.
  2. DI kodunu test etmek çok daha kolaydır. Nesne tarafından ifade edilen işlevsellik, uygulama mantığınız tarafından beklenen arabirimleri uygulayan 'sahte' nesneler oluşturarak bir kara kutuda test edilebilir.
  3. DI kodu daha esnektir. Doğuştan gevşek bağlı bir koddur - aşırıya. Bu, programcının nesnelerin nasıl bağlanacağını, yalnızca bir uçtaki gerekli arabirimlere ve diğer uçtaki ifade arabirimlerine göre seçmesine ve seçmesine olanak tanır.
  4. DI nesnelerinin harici (Xml) yapılandırması, başkalarının kodunuzu öngörülemeyen yönlerde özelleştirebileceği anlamına gelir.
  5. Dış konfigürasyon ayrıca, nesne başlatma ve nesne karşılıklı bağımlılığı yönetimine ilişkin tüm sorunların uygulama sunucusu tarafından ele alınabilmesi açısından bir endişe modelidir.
  6. DI modelini kullanmak için harici konfigürasyonun gerekli olmadığını unutmayın, basit ara bağlantılar için küçük bir oluşturucu nesne genellikle yeterlidir. İkisi arasında esneklikte bir değiş tokuş var. Bir oluşturucu nesnesi, harici olarak görülebilir bir yapılandırma dosyası kadar esnek bir seçenek değildir. DI sisteminin geliştiricisi, bir konfigürasyon dosyasında ifade edildiği gibi, nesne yapımı üzerindeki küçük ölçekli, ince taneli kontrolün, hattaki karışıklığı ve bakım maliyetlerini artırabileceğine dikkat ederek, esnekliğin rahatlığa göre avantajlarını tartmalıdır.

Kesinlikle DI kodu daha hantal görünüyor, nesneleri diğer nesnelere enjekte edilecek şekilde yapılandıran tüm bu XML dosyalarına sahip olmanın dezavantajları zor görünüyor. Ancak bu, DI sistemlerinin amacıdır. Kod nesnelerini bir dizi yapılandırma ayarı olarak karıştırma ve eşleştirme beceriniz, parçanızda minimum kodlama ile 3. taraf kodunu kullanarak karmaşık sistemler oluşturmanıza olanak tanır.

Soruda verilen örnek, yalnızca uygun şekilde çarpanlara ayrılmış bir DI nesne kitaplığının sağlayabileceği ifade gücünün yüzeyine dokunmaktadır. Bazı pratikler ve çok sayıda öz disiplin uygulayan çoğu DI pratisyeni, uygulama kodunun% 100 test kapsamına sahip sistemler oluşturabileceklerini fark eder. Tek başına bu tek nokta olağanüstü. Bu, birkaç yüz satır koddan oluşan küçük bir uygulamanın% 100 test kapsamı değil, yüz binlerce kod satırı içeren uygulamaların% 100 test kapsamıdır. Bu test edilebilirlik düzeyini sağlayan başka herhangi bir tasarım modelini tanımlayamıyorum.

Sadece 10 satırlık koddan oluşan bir uygulamanın anlaşılması, birkaç nesne ve bir dizi XML yapılandırma dosyasından daha kolay anlaşılır olduğu konusunda haklısınız. Bununla birlikte, en güçlü tasarım modellerinde olduğu gibi, sisteme yeni özellikler eklemeye devam ettiğinizde kazançlar bulunur.

Kısacası, büyük ölçekli DI tabanlı uygulamaların hem hata ayıklaması hem de anlaşılması daha kolaydır. Xml yapılandırması 'derleme zamanı kontrol edilmemiş olsa da, bu yazarın bildiği tüm uygulama hizmetleri, uyumsuz bir arayüze sahip bir nesneyi başka bir nesneye enjekte etmeye çalışırlarsa geliştiriciye hata mesajları sağlayacaktır. Ve çoğu, bilinen tüm nesne konfigürasyonlarını kapsayan bir 'kontrol' özelliği sağlar. Bu, enjekte edilecek nesne A'nın, yapılandırılmış tüm nesne enjeksiyonları için B nesnesinin gerektirdiği arabirimi uyguladığının kontrol edilmesiyle kolayca ve hızlı bir şekilde yapılır.


4
DI'nin faydalarını anlar. Aynı şeyi yapan kodu yapılandırmaya kıyasla harici XML yapılandırmasının hangi faydaları eklediğini anlamıyorum. Bahsettiğiniz faydalar DI tasarım modeli tarafından sağlanmaktadır. Soru, düz başlatma koduna kıyasla DI yapılandırmasının faydalarıyla ilgiliydi.
Pavel Feldman

> Harici konfigürasyon da bir ayrımdır ... Konfigürasyonun ayrılması, iyi olan DI'nin kalbidir. Ve başlatma kodunu kullanarak kubbe oluşturabilir. Kodu başlatmaya kıyasla cfg ne ekler? Benim için her cfg satırının karşılık gelen başlatma kod satırına sahip olduğu görülüyor.
Pavel Feldman

7

Bu biraz yüklü bir soru, ancak büyük miktarlarda xml yapılandırmasının gerçekten çok fazla fayda sağlamadığına katılıyorum. Uygulamalarımın ağır çerçeveler de dahil olmak üzere bağımlılıklara olabildiğince hafif olmasını seviyorum.

Çoğu zaman kodu basitleştirirler, ancak aynı zamanda sorunları takip etmeyi oldukça zorlaştıran karmaşık bir ek yüke sahiptirler (bu tür sorunları ilk elden gördüm ve doğrudan Java ile uğraşmak çok daha rahat olurdu).

Sanırım bu biraz stile ve neyle rahat olduğunuza bağlı ... kendi çözümünüzü uçurmaktan ve onu içten dışa bilmenin avantajına sahip olmaktan veya yapılandırma olmadığında zor olabilecek mevcut çözümlerden yararlanmaktan hoşlanıyor musunuz? doğru mu? Hepsi bir değiş tokuş.

Bununla birlikte, XML yapılandırması benim için biraz evcil hayvanım ... Ne pahasına olursa olsun bundan kaçınmaya çalışıyorum.


5

Kodunuzu verilerle değiştirebildiğiniz her an, doğru yönde bir adım atmış olursunuz.

Herhangi bir şeyi veri olarak kodlamak, kodunuzun kendisinin daha genel ve yeniden kullanılabilir olduğu anlamına gelir. Ayrıca, verilerinizin ona tam olarak uyan bir dilde belirtilebileceği anlamına gelir.

Ayrıca, bir XML dosyası bir GUI'ye veya başka bir araca okunabilir ve pragmatik olarak kolayca değiştirilebilir. Bunu kod örneğiyle nasıl yaparsınız?

Çoğu insanın veriye kod olarak uygulayacağı şeyleri sürekli olarak hesaba katıyorum, bu, hangi kodun ÇOK daha temiz bırakılmasını sağlar. İnsanların veri yerine kodda bir menü oluşturmasını akıl almaz buluyorum - bunu kodda yapmanın, şablon yüzünden tamamen yanlış olduğu aşikar olmalı.


mantıklı, bu açıdan düşünmedi
Pavel Feldman

7
sonra tekrar, insanlar genellikle diğer tarafa gider ve verilere mantık koymaya çalışır, bu da uygulamanızı standart altı bir programlama dilinde kodlamanız anlamına gelir
Casebash

@Casebash Bu ilginç bir bakış açısı - Bir örnekle inanılmaz derecede ilgilenirim. Verilere taşıyabileceğim her şeyin yardımcı olduğunu görüyorum. Ayrıca, dediğinizi tam olarak yaparsam, dilin bir DSL olduğu için aslında geliştirildiğini fark ettim - ama o zaman bile tamamen yeni bir dil yaratmak için ciddi gerekçelendirme gerekiyor.
Bill K

1
"Kodunuzu veriye her değiştirebildiğinizde doğru yönde bir adım atıyorsunuz." Yumuşak Kodlama anti-kalıbına hoş geldiniz.
Raedwald

@Raedwald Bahsettiğiniz şey, dışsallaştırmaktır ki, ne yaptığınızı bilmiyorsanız (ve beceriksiz birinin bunu denemesinin, başarısız olmasının ve buna anti-model adını vermesinin nedeni) gerçekten zor olabilir. Daha olumlu örnekler Enjeksiyon, Yineleyiciler olabilir , ek açıklamalı hemen hemen her şey, dizilerle başlayan her şey. Çoğu harika programlama yapısı, kodunuzdaki farklılıkları ayırma ve kalanları birleştirerek onu daha iyi gruplanabilen ve yönetilebilen bir şeyle çalıştırma girişimidir.
Bill K

3

Bir DI kapsayıcısı kullanmanın nedeni, kodunuzda yalnızca alıcılar ve ayarlayıcılar olan önceden yapılandırılmış bir milyar özelliğe sahip olmanız gerekmemesidir. Tüm bunları yeni X () ile kodlamak gerçekten istiyor musunuz? Elbette bir varsayılanınız olabilir, ancak DI kapsayıcısı, son derece kolay olan ve onu başlatma gibi çeşitli görevlere değil, kodun ayrıntılarına odaklanmanıza izin veren tekillerin oluşturulmasına izin verir.

Örneğin, Spring, InitializingBean arabirimini uygulamanıza ve afterPropertiesSet yöntemi eklemenize olanak tanır (kodunuzu Spring'e bağlamayı önlemek için bir "init yöntemi" de belirtebilirsiniz). Bu yöntemler, sınıf örneğinizde bir alan olarak belirtilen herhangi bir arabirimin başlangıçta doğru şekilde yapılandırıldığından emin olmanıza olanak tanır ve artık alıcılarınızı ve ayarlayıcılarınızı sıfır kontrol etmeniz gerekmez (tekli tonlarınızın iş parçacığı güvenli kalmasına izin verdiğinizi varsayarak) ).

Dahası, karmaşık başlatmaları kendi başınıza yapmak yerine bir DI kapsayıcısıyla yapmak çok daha kolaydır. Örneğin, XFire kullanımına yardımcı oluyorum (CeltiXFire değil, sadece Java 1.4 kullanıyoruz). Uygulama Spring'i kullandı, ancak ne yazık ki XFire'ın services.xml yapılandırma mekanizmasını kullandı. Bir öğe koleksiyonunun BİR veya daha fazla örnek yerine SIFIR veya daha fazla örneğe sahip olduğunu bildirmesi gerektiğinde, bu belirli hizmet için sağlanan XFire kodunun bazılarını geçersiz kılmak zorunda kaldım.

Bahar fasulyesi şemasında tanımlanmış belirli XFire varsayılanları vardır. Yani, eğer hizmetleri yapılandırmak için Spring'i kullanıyor olsaydık, çekirdekler kullanılabilirdi. Bunun yerine, fasulyeleri kullanmak yerine services.xml dosyasında belirli bir sınıfın bir örneğini sağlamam gerekti. Bunu yapmak için, kurucuyu sağlamam ve XFire konfigürasyonunda belirtilen referansları ayarlamam gerekiyordu. Yapmam gereken gerçek değişiklik, tek bir sınıfı aşırı yüklememi gerektiriyordu.

Ancak services.xml dosyası sayesinde dört yeni sınıf oluşturmak zorunda kaldım, varsayılanlarını oluşturuculardaki Spring yapılandırma dosyalarındaki varsayılanlarına göre ayarladım. Yay konfigürasyonunu kullanabilseydik, şunu söyleyebilirdim:

<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" />

Bunun yerine, daha çok şuna benziyordu:

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
    }
}

Dolayısıyla net sonuç, bir ek sınıfın ve bazı basit bağımlılık kapsayıcı bilgilerinin elde ettiği etkiyi elde etmek için kod tabanına dört ek, çoğunlukla anlamsız Java sınıfının eklenmesi gerektiğidir. Bu, "kuralı kanıtlayan istisna" değildir, kural budur ... koddaki tuhaflıkları ele almak, özellikler zaten bir DI kapsayıcısında sağlandığında ve bunları özel bir duruma uyacak şekilde değiştirdiğinizde çok daha temizdir, ki bu daha sık olur.


3

Cevabını aldım

Açıkça her yaklaşımda ödünleşmeler vardır, ancak haricileştirilmiş XML yapılandırma dosyaları, IDE'nizi değil kodu derlemek için yapı sistemlerinin kullanıldığı kurumsal geliştirme için kullanışlıdır. Derleme sistemini kullanarak, kodunuza belirli değerleri enjekte etmek isteyebilirsiniz - örneğin, yapının sürümü (her derleme yaptığınızda manuel olarak güncelleme yapmak zahmetli olabilir). Derleme sisteminiz bazı sürüm kontrol sistemlerinden kodu çektiğinde acı daha da artar. Derleme zamanında basit değerleri değiştirmek, bir dosyayı değiştirmenizi, kaydetmenizi, derlemenizi ve ardından her değişiklik için her seferinde geri dönmenizi gerektirir. Bunlar, sürüm kontrolünüze dahil etmek istediğiniz değişiklikler değildir.

Derleme sistemi ve harici yapılandırmalarla ilgili diğer yararlı kullanım örnekleri:

  • farklı yapılar için tek bir kod tabanı için stil / stil sayfaları enjekte etme
  • tek kod tabanınız için farklı dinamik içerik kümeleri (veya bunlara referanslar) enjekte etmek
  • farklı yapılar / istemciler için yerelleştirme bağlamı enjekte etme
  • bir web hizmeti URI'sini yedekleme sunucusuna dönüştürmek (ana sunucu çöktüğünde)

Güncelleme: Yukarıdaki tüm örnekler, sınıflara bağımlılık gerektirmeyen şeyler üzerineydi. Ancak hem karmaşık bir nesnenin hem de otomasyonun gerekli olduğu durumları kolayca oluşturabilirsiniz - örneğin:

  • Web sitenizin trafiğini izlediği bir sisteminiz olduğunu hayal edin. Eşzamanlı kullanıcı sayısına bağlı olarak, bir günlük kaydı mekanizmasını açar / kapatır. Belki de mekanizma kapalıyken, yerine bir saplama nesnesi yerleştirilir.
  • Kullanıcı sayısına bağlı olarak, katılımcı sayısına bağlı olarak P2P yapma özelliğini değiştirmek istediğiniz bir web konferans sisteminiz olduğunu hayal edin.

En üstte kurumsal yönü vurgulamak için +1. Kötü yazılmış eski kodu test etmek, bazen günlerce süren bir kabus olabilir.
Richard Le Mesurier

2

Yapılandırmada her değişiklik yaptığınızda, kodunuzu yeniden derlemenize gerek yoktur. Program dağıtımını ve bakımını basitleştirecektir. Örneğin, yapılandırma dosyasında sadece 1 değişiklikle bir bileşeni diğeriyle değiştirebilirsiniz.


dağıtım? muhtemelen ... dağıtımın sürdürülmesi? muhtemelen ... kodun bakımı? Hayır diye düşünmeye meyilliyim ... çerçeveler aracılığıyla hata ayıklamanın büyük bir baş ağrısı olma eğilimindedir ve bu konuda pojoların üstesinden gelmek çok daha kolaydır.
Mike Stone

1
Mike, kod hakkında hiçbir şey söylemedim. XML yapılandırmasının berbat olduğunu hepimiz biliyoruz :)
aku

Hmm .. bileşenleri yeniden derlemeden ne sıklıkla değiştiriyorsunuz ve ne için? Birisinin DB kimlik bilgilerini değiştirip programı yeniden derlemek istemediğini anlıyorum - onu geliştiren kişi o olmayabilir. Ancak geliştiricinin yay yapılandırmasını değiştirmekten başka birini hayal edemiyorum
Pavel Feldman

Pavel genellikle bu durum, programı yüzlerce istemciye dağıtmanız gerektiğinde ortaya çıkar. Böyle bir durumda, ürünün yeni sürümünü kullanmak yerine yapılandırmayı değiştirmek çok daha kolaydır. Geliştiriciler hakkında haklısın. Genellikle geliştirici yeni cfg oluşturur ve yönetici onu dağıtır.
aku

2

Kız arkadaş için yeni bir uygulama yerleştirebilirsiniz. Böylece yeni dişi, kodunuzu yeniden derlemeden enjekte edilebilir.

<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>

(Yukarıdakiler, Female ve HotFemale'in aynı GirlfFriend arayüzünü uyguladığını varsayar)


Yeniden derlemeden mantık değişiklikleri neden iyi bir fikir olarak kabul edilir?
Pavel Feldman

Kesinlikle HotFemale yapabilirim jane = new HotFmale (); jane.setAge (19); john.setGirlfriend (jane); Yani tek fark, cfg'nin yeniden derlenmeden değiştirilebilmesidir? Bahar tartışıldığında bu yaygın bir cevap gibi görünüyor. Neden?! Derlemekten kaçınmak neden iyidir?
Pavel Feldman

Kodu daha iyi test edebilirim, Dişi Nesne ile alay edebilirim.
Paul Whelan

@Pavel Feldman: çünkü uygulamanızı zaten istemcide dağıttıysanız, bu daha kolaydır.
Andrei Rînea

1

.NET dünyasında, IoC çerçevelerinin çoğu hem XML hem de Kod yapılandırması sağlar.

Örneğin, StructureMap ve Ninject, kapsayıcıları yapılandırmak için akıcı arayüzler kullanır. Artık XML yapılandırma dosyalarını kullanmakla sınırlı değilsiniz. .NET'te de bulunan Spring, tarihsel ana yapılandırma arayüzü olduğu için büyük ölçüde XML dosyalarına güvenir, ancak kapsayıcıları programlı olarak yapılandırmak yine de mümkündür.


Sonunda, kullanılması amaçlanan şey için kodu kullanabilmem harika :) Ama böyle şeyler yapmak için neden programlama dilinden başka bir şeye ihtiyacım var?
Pavel Feldman

Bunun nedeni, XML'in projeyi yeniden derlemek zorunda kalmadan çalışma zamanı değişikliklerine veya en azından yapılandırma değişikliklerine izin vermesidir.
Romain Verdier

1

Kısmi konfigürasyonları nihai bir tam konfigürasyonda birleştirme kolaylığı .

Örneğin, web uygulamalarında model, görünüm ve kontrolörler tipik olarak ayrı konfigürasyon dosyalarında belirtilir. Bildirime dayalı yaklaşımı kullanın, örneğin yükleyebilirsiniz:

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

Veya farklı bir kullanıcı arayüzü ve birkaç ekstra denetleyici ile yükleyin:

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

Aynısını kodda yapmak için kısmi konfigürasyonları birleştirmek için bir altyapı gerekir. Kodda yapmak imkansız değil, ancak bir IoC çerçevesi kullanarak yapılması kesinlikle daha kolay.


1

Genellikle önemli olan nokta, program yazıldıktan sonra yapılandırmayı kimin değiştirdiğidir. Kodda yapılandırma ile, onu değiştiren kişinin orijinal yazarla aynı becerilere ve kaynak koduna erişime sahip olduğunu varsayarsınız.

Üretim sistemlerinde, bazı ayar alt kümelerini (örneğin, örneğinizde yaş) XML dosyasına çıkarmak ve örneğin sistem yöneticisi veya destek personelinin kaynak kodu veya diğer ayarlar üzerinde tam güç vermeden değeri değiştirmesine izin vermek çok pratiktir - veya sadece onları karmaşıklıklardan izole etmek için.


Bu geçerli bir nokta, ancak yay konfigürasyonu genellikle oldukça karmaşık olma eğilimindedir. Yaşı değiştirmek kolay olsa da, sysadmin yine de tamamen anlamasına gerek olmadığı büyük xml dosyasıyla uğraşmak zorundadır. Spring XML yapılandırmasından daha basit bir şeye yapılandırılması gereken kısmı çıkarmak daha iyi değil mi? Özellikler dosyası gibi, tek satırlık "age = 23" ve yöneticinin dahili program yapısı bilgisi gerektiren sınıf adları vb. Gibi diğer ayrıntıları değiştirmesine izin vermeyin.
Pavel Feldman

Geçenlerde Java kodu ve XSLT'nin karışımını içeren bir proje üzerinde çalışıyordum. Ekip, Java konusunda güçlü olan (ve belki de XML ve XSLT ile çalışma konusunda daha az rahat olan) insanlardan oluşan bir karışımdı; ve XML ve XSLT ile çok güçlü (ve Java ile daha az rahat) çalışan kişiler. Yapılandırma ikinci grup tarafından yönetileceğinden, Spring'i kullanmak ve XML yapılandırmalarına sahip olmak mantıklıydı. Başka bir deyişle, Bahar takımdaki bir iş bölümü sorununu çözdü. "Teknik" bir sorunu çözmedi; yani yapılandırmanın Java kodu ile aynı kolaylıkla yapılabilmesi.
Dawood ibn Kareem

'Destek personeli' bir bağımlılık enjeksiyon konteynerinde yaratılan bazı sınıfları değiştirmek zorunda olduğunu ne zaman bilir? Gerçekten bunu yapmanın bir geliştiricinin işi olduğu varsayımı altında mı?
Jimbo

Konfigürasyon değerlerini (örneğin entegre ettiğiniz sistemin URL'si) çıkarmanın mantıklı olmasının nedeni budur: destek personeli özellikler dosyasını veya (en kötü durumda) XML dosyasını düzenler, derlenen Java sınıfı aynı kalır.
Miro A.

1

Bahar perspektifinden size iki cevap verebilirim.

Öncelikle, XML yapılandırması, yapılandırmayı tanımlamanın tek yolu değildir. Çoğu şey ek açıklamalar kullanılarak yapılandırılabilir ve XML ile yapılması gereken şeyler, bir kitaplıktan kullandığınız bir bağlantı havuzu gibi yine de yazmadığınız kod için yapılandırmadır. Yay 3, örneğinizdeki elle haddelenmiş DI yapılandırmasına benzer şekilde Java kullanarak DI yapılandırmasını tanımlamak için bir yöntem içerir. Yani Spring kullanmak, XML tabanlı bir yapılandırma dosyası kullanmanız gerektiği anlamına gelmez.

İkincisi, Bahar sadece bir DI çerçevesinden çok daha fazlasıdır. İşlem yönetimi ve AOP dahil olmak üzere birçok başka özelliğe sahiptir. Spring XML yapılandırması tüm bu kavramları bir araya getirir. Çoğunlukla aynı yapılandırma dosyasında fasulye bağımlılıklarını, işlem ayarlarını belirtiyorum ve arka planda AOP kullanarak gerçekten işlenen oturum kapsamlı fasulye ekliyorum. XML yapılandırmasının tüm bu özellikleri yönetmek için daha iyi bir yer sağladığını düşünüyorum. Ayrıca açıklama tabanlı yapılandırma ve XML yapılandırmasının ölçeklendirmenin Java tabanlı yapılandırmaya göre daha iyi olduğunu düşünüyorum.

Ama amacınızı anlıyorum ve Java'da bağımlılık enjeksiyon yapılandırmasını tanımlamada yanlış bir şey yok. Normalde bunu birim testlerinde kendim yapıyorum ve bir DI çerçevesi eklemediğim kadar küçük bir proje üzerinde çalışırken. Normalde Java'da konfigürasyon belirtmiyorum çünkü bana göre Spring'i kullanmayı seçtiğimde yazmaktan uzaklaşmaya çalıştığım türden bir tesisat kodu. Bu bir tercih olsa da, XML yapılandırmasının Java tabanlı yapılandırmadan daha üstün olduğu anlamına gelmez.


0

Yay ayrıca bir özellik yükleyiciye sahiptir. Bu yöntemi, ortama bağlı değişkenleri ayarlamak için kullanırız (örn. Geliştirme, test etme, kabul etme, üretim, ...). Bu, örneğin dinlenmek için kuyruk olabilir.

Özelliğin değişmesi için bir neden yoksa, bu şekilde yapılandırmak için de bir neden yoktur.


0

Durumunuz çok basittir ve bu nedenle Spring gibi bir IoC (Kontrolün Ters Çevrilmesi) konteynırına ihtiyaç duymaz. Öte yandan, "uygulamalara değil arayüzlere programladığınızda" (bu, OOP'de iyi bir uygulamadır), aşağıdaki gibi koda sahip olabilirsiniz:

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

(myService türünün IService olduğunu unutmayın - somut bir uygulama değil, bir arayüz). Artık IoC konteynerinizin başlatma sırasında otomatik olarak doğru somut IService örneğini sağlamasına izin vermek kullanışlı olabilir - birçok arayüzünüz ve birçok uygulamaya sahip olduğunuzda, bunu elle yapmak zahmetli olabilir. Bir IoC konteynerinin (bağımlılık ekleme çerçevesi) başlıca faydaları şunlardır:

  • Arayüzler ve somut uygulamaları arasında haritalamanın harici konfigürasyonu
  • IoC konteyneri, karmaşık bağımlılık grafiklerini çözme, bileşenin ömrünü yönetme vb. Gibi bazı zorlu sorunları ele alır.
  • Eşlemeleri prosedürel kodda değil, bildirimli olarak sağladığınız için kodlama süresinden tasarruf edersiniz
  • Kontrolü Ters Çevirme ilkesi, gerçek uygulamaları sahte olanlarla değiştirebileceğiniz için kolay birim testine izin verir (SQL veritabanını bellek içi biriyle değiştirmek gibi)

0

Bir XML yapılandırma dosyasında başlatma, uygulamanızı bilgisayarlarına dağıtan bir istemciyle yaptığınız hata ayıklama / uyarlama işinizi basitleştirir. (Çünkü yeniden derleme + ikili dosyaların değiştirilmesini gerektirmez)


-2

En çekici nedenlerden biri " Hollywood prensibi " dir: bizi arama, biz sizi arayalım. Diğer bileşenlere ve hizmetlere arama yapmak için bir bileşene gerek yoktur; bunun yerine otomatik olarak sağlanırlar. Java'da bu, artık bileşen içinde JNDI aramalarının yapılmasına gerek olmadığı anlamına gelir.

Bir bileşeni tek başına birim test etmek de çok daha kolaydır: ona ihtiyaç duyduğu bileşenlerin gerçek bir uygulamasını vermek yerine, basitçe (muhtemelen otomatik olarak oluşturulmuş) alayları kullanırsınız.


Bu cevap bağımlılık enjeksiyonu ile ilgilidir. Ne olduğunu biliyorum, iyi olduğunu biliyorum ve sorunun ilk cümlesinde açıkça ifade ediyorum. Soru, düz başlatma koduna kıyasla DI yapılandırmasının faydalarıyla ilgiliydi.
Pavel Feldman

Soruya gerçekten cevap vermiyor
Casebash
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.