IOC Konteynerleri OOP İlkelerini çiğniyor


51

IOC Konteynerlerinin amacı nedir? Bunun için birleştirilmiş sebepler aşağıdakilerle basitleştirilebilir:

OOP / SOLID Development prensiplerini kullanırken, Bağımlılık Enjeksiyonu dağınık hale gelir. Ya üst seviyedeki giriş noktalarına sahip olmanız, alt seviyelerdeki bağımlılıkları yönetme ve bağımlılıkları inşaat boyunca yinelemeli olarak geçirme ya da fabrika / imalatçı modellerinde ve ihtiyaç duyduğunuzda bağımlılıkları oluşturan arayüzlerde yinelenen bir kodunuz vardır.

Bunu gerçekleştirmek için OOP / SOLID yolu yoktur VE süper güzel kodlara sahiptir.

Bu önceki ifade doğruysa, IOC Containers bunu nasıl yapar? Bildiğim kadarıyla, manuel DI ile yapılamayan bilinmeyen bir teknik kullanmıyorlar. Dolayısıyla tek açıklama, IOC Containers'ın statik nesneleri özel erişim sağlayıcıları kullanarak OOP / SOLID Prensiplerini çiğnemesidir.

IOC Konteynerleri perde arkasında aşağıdaki prensipleri ihlal ediyor mu? Bu iyi bir anlayışa sahip olduğum için asıl soru, ancak başkasının daha iyi bir anlayışa sahip olduğunu hissediyorum:

  1. Kapsam kontrolü . Kapsam, kod tasarımımda verdiğim hemen hemen her kararın nedeni. Blok, Yerel, Modül, Statik / Global. Kapsam, blok düzeyinde ve olabildiğince az Statik olarak çok açık olmalıdır. Bildirimleri, örneklemeleri ve yaşam döngüsü sonlarını görmelisiniz. Açıkça kullandığım sürece, kapsamı yönetmek için dile ve GC'ye güveniyorum. Araştırmamda, IOC Containers'ın bağımlılıkların çoğunu veya tümünü Statik olarak kurduğunu ve sahnelerin arkasındaki bazı AOP uygulamalarını kontrol ettiğini buldum. Yani hiçbir şey şeffaf değil.
  2. Kapsülleme . Kapsülleme amacı nedir? Neden özel üye tutmalıyız? Pratik nedenlerden dolayı, API'mızın uygulayıcıları devleti değiştirerek (sahip sınıf tarafından yönetilmesi gereken) durumu değiştirerek uygulamayı bozamazlar. Ancak, güvenlik nedeniyle, üye devletlerimizi ele geçiren ve onaylama ve sınıf kontrolünü atlayan enjeksiyonlar gerçekleşemez. Bu nedenle, özel üyelere dış erişim sağlamak için derleme zamanından önce bir şekilde kod enjekte eden herhangi bir şey (Mocking çerçeveleri veya IOC çerçeveleri) oldukça büyüktür.
  3. Tek Sorumluluk İlkesi . Yüzeyde, IOC Containers işleri daha temiz hale getiriyor. Ancak, aynı şeyleri yardımcı çerçeveler olmadan nasıl başaracağınızı hayal edin. Bir düzine kadar bağımlılığı olan inşaatçılara sahip olacaksınız. Bu, IOC Containers ile örtülmesi anlamına gelmiyor, bu iyi bir şey! Bu, kodunuzu tekrar değerlendirmek ve SRP'yi takip etmek için bir işarettir.
  4. Kapalı / Açık . Tıpkı SRP'nin Sadece Sınıf olmadığı gibi (Ben, tek başına sorumluluk satırlarına, yöntemleri yalnız bırakarak SRP'yi uygularım). Açık / Kapalı, bir sınıfın kodunu değiştirmemek için sadece yüksek düzeyde bir teori değildir. Programınızın konfigürasyonunu anlama ve neyin değiştirilip neyin uzatılacağı üzerinde kontrol sahibi olma pratiğidir. IOC Containers, sınıflarınızın tamamen çalışma şeklini kısmen değiştirebilir çünkü:

    • a. Ana kod, bağımlılıkların kapatılmasını belirleme değil, çerçeve yapılandırmasıdır.

    • b. Kapsam, arayan üyeler tarafından kontrol edilmeyen bir zamanda değiştirilebilir, bunun yerine harici olarak statik bir çerçeve tarafından belirlenir.

Bu yüzden sınıfın yapılandırması gerçekten kapalı değil, üçüncü parti bir aracın yapılandırmasına bağlı olarak kendini değiştiriyor.

Bu sorunun bir nedeni, zorunlu olarak tüm IOC Konteynerlerinin ustası olmamamdır. Ve bir IOC Konteyner fikri güzel olsa da, sadece zayıf uygulamayı kapsayan bir cephe gibi görünüyorlar. Ancak dış Kapsam kontrolü, Özel üye erişimi ve Tembel yükleme işlemini gerçekleştirmek için, önemsiz sorgulanmayacak birçok şeyin devam etmesi gerekiyor. AOP harika, ancak IOC Containers aracılığıyla gerçekleştirilme şekli de sorgulanabilir.

C # 'ya ve .NET GC’ye beklediğim şeyi yapacağına güvenebilirim. Ancak, aynı güveni, el ile yapamadığım şeylere geçici çözümler uygulamak için derlenmiş kodumu değiştiren üçüncü taraf bir araca koyamıyorum.

EG: Entity Framework ve diğer ORM'ler, güçlü Typed nesneler yaratır ve bunları veritabanı varlıklarına eşleştirir, ayrıca CRUD gerçekleştirmek için kazan plakası temel işlevselliği sağlar. Herkes kendi ORM'sini oluşturabilir ve OOP / SOLID İlkelerini manuel olarak takip etmeye devam edebilir. Ancak bu çerçeveler bize yardımcı oluyor, böylece her seferinde tekerleği yeniden icat etmemize gerek kalmıyor. Oysa IOC Konteynerleri, bilerek OOP / SOLID Prensipleri çevresinde çalışmamıza ve bunları korumamıza yardımcı oluyor.


13
+1 Arasındaki korelasyon IOCve Explicitness of codetam olarak sorunum olan şey. Manüel DI kolayca bir angarya haline gelebilir, ancak en azından kendi kendine yeten açık program akışını tek bir yere koyar - "Gördüğünüzü alırsın, ne alırsın görürsün". IOC konteynerlerinin bağları ve beyanları kolayca kendi başına gizli bir paralel program haline gelebilir.
Eugene Podskal

6
Bu nasıl bir soru?
Stephen

8
Bu bir sorudan çok bir blog yazısı gibi görünüyor.
Bart van Ingen Schenau

4
“Resmi tartışmacı” olan sorular için içsel bir kategoriye sahibim, bu da resmi bir yakın sebep değil, ancak "gerçek bir soruyu" kapatmak için bile oy kullanmıyor ve bazen oy kullanabiliyorum. Yine de iki yönü var ve bu soru yalnızca ilk soruyu karşılıyor. (1) Soru bir tezi belirtir ve doğru olup olmadığını sorar, (2) soru soran ilk pozisyonu savunan cevap vermez. Matthew’ün cevabı, sorunun ne anlama geldiğinin bir kısmıyla çelişiyor, bu yüzden, sorgulayıcı her şeyi taramadığı sürece, bunu “ben haklımıyım, değil mi?” Biçiminde de olsa, şahsen iyi niyetli bir soru olarak kategorize ediyorum.
Steve Jessop

3
@ BenAaronson Teşekkürler Ben. Araştırmamla öğrendiklerimi iletmeye çalışıyorum ve IOC Konteynerlerinin doğası hakkında cevaplar almaya çalışıyorum. Araştırmamın sonucunda bu ilkelerin kırıldığını tespit ettim. Soruma en iyi cevap, IOC Containers'ın bir şekilde OOP / SOLID Prensiplerini bozmadan manuel olarak yapamayacağımız şeyleri yapabileceğini onaylar veya reddeder. Harika yorumlarınız nedeniyle, sorumu daha fazla örnekle yeniden sorguladım.
Suamere

Yanıtlar:


35

Sayılarınızı sayısal olarak inceleyeceğim, ama önce, çok dikkatli olmanız gereken bir şey var: bir tüketicinin bir kütüphaneyi, kütüphanenin nasıl uygulandığı ile nasıl kullandığıyla ilgilenmeyin . Buna güzel örnekler Entity Framework (sizin iyi bir kütüphane olarak bahsettiğiniz) ve ASP.NET'in MVC'sidir. Bunların her ikisi de, örneğin günlük kodla yayılırsa kesinlikle iyi bir tasarım olarak kabul edilmeyen yansıma ile kaputun altında çok fazla şey yapar.

Bu kütüphaneler kesinlikle vardır değil nasıl çalıştıkları "Şeffaf", ya da sahne arkası yapıyoruz. Fakat bu bir zarar değil, çünkü tüketicilerinde iyi programlama ilkelerini destekliyorlar . Dolayısıyla, ne zaman böyle bir kütüphane hakkında konuşursanız, bir kütüphane tüketicisi olarak, uygulamasından veya bakımından endişelenmek sizin işiniz olmadığını unutmayın. Yalnızca, kitaplığı kullanan yazdığınız kodun nasıl yardımcı olacağı veya engelleneceği konusunda endişelenmelisiniz. Bu kavramları birbirine bağlamayın!

Yani, noktadan geçmek için:

  1. Hemen kabul edebileceğim şeye ulaşıyoruz, yukarıdakilerin bir örneği. IOC konteynerlerinin çoğu bağımlılığı statik olarak kurduğunu söylüyorsunuz. Eh, belki de nasıl çalıştıklarına dair bazı uygulama detayları statik depolamayı da içeriyor (Ninject'inki gibi bir nesne örneğini IKernelçekirdek depo olarak kullanma eğiliminde olsalar bile, bundan şüpheliyim). Ama bu senin endişen değil!

    Aslında, bir IoC konteyneri, fakir insanın bağımlılık enjeksiyonunun kapsamı kadar açıktır. (IoC konteynerlerini yoksul adamın DI'siyle karşılaştırmaya devam edeceğim çünkü onları hiç DI ile karşılaştırmak haksızlık ve kafa karıştırıcı olacaktır.

    Zavallı adamın DI'sinde, bir bağımlılığı manüel olarak başlatırsın, sonra ihtiyacı olan sınıfa enjekte edersin. Bağımlılığı oluşturduğunuz noktada, onunla ne yapılacağını seçersiniz - yerel olarak genişletilmiş bir değişkende, bir sınıf değişkeninde, statik bir değişkende, ne olursa olsun saklamayın. Aynı örneği birçok sınıfa geçirebilir veya her sınıf için yeni bir tane oluşturabilirsiniz. Her neyse. Önemli olan, hangisinin olduğunu görmek için, bağımlılığın yaratıldığı noktaya (muhtemelen uygulama kökünün yakınında) bakarsınız.

    Şimdi bir IoC kabı ne olacak? Tamamen aynısını yapıyorsun! Yine Ninject terminolojisi ile edeceksen, bağlayıcı kurulduğundan nereye bakmak ve bulmak diyor ister gibi bir şey InTransientScope, InSingletonScopeya da her neyse. Eğer herhangi bir şey potansiyel olarak daha netse, orada bir kod var, çünkü bir nesneye ne olduğunu izlemek için bir metoda bakmak yerine, kapsamını açıklayan bir kod var. engelle veya yalnızca bir kez, örneğin). Belki de kapsamı dikte etmek için ham bir dil özelliği yerine IoC konteynerinde bir özellik kullanma zorunluluğunuz var, ancak IoC kütüphanenize güvendiğiniz sürece - ki bunun için dezavantajınız yok! .

  2. Burada neden bahsettiğini hala bilmiyorum. IoC konteynerleri özel mülklere iç uygulamalarının bir parçası olarak mı bakıyor? Neden olduklarını bilmiyorum ama yine de yaparlarsa, kullandığınız bir kütüphanenin nasıl uygulanacağı sizin endişeniz değil.

    Ya da belki de özel ayarlayıcılara enjekte etme gibi bir yetenek sergiliyorlar mı? Açıkçası bununla hiç karşılaşmadım ve bunun gerçekten ortak bir özellik olup olmadığı konusunda şüpheliyim. Fakat orada olsa bile, kötüye kullanılabilecek bir alet basit bir durumdur. Unutmayın, bir IoC kabı olmasa bile, özel bir özelliğe erişmek ve bunları değiştirmek için kullanılan birkaç Yansıma kodundan başka bir şey değildir. Neredeyse hiç yapmamanız gereken bir şey, ancak bu, .NET'in bu özelliği ortaya çıkarmakta kötü olduğu anlamına gelmez. Biri bir aleti açıkça ve çılgınca kötüye kullanırsa, bu, aracın değil kişinin hatasıdır.

  3. Buradaki nihai nokta 2'ye benziyor. Zamanın büyük çoğunluğu, IoC konteynerleri yapıcıyı kullanıyor! Setter enjeksiyonu, özel sebeplerden dolayı, yapıcı enjeksiyonun kullanılamadığı çok özel durumlar için sunulmaktadır. Kaç tane bağımlılığın geçtiğini örtbas etmek için sürekli olarak setter enjeksiyonu kullanan herkes, aracı kitlesel olarak terk ediyor. Bu, aracın hatası değil, onların.

    Şimdi, eğer bu masum bir şekilde yapmak gerçekten kolay bir hataydıysa ve IoC konteynerlerinin cesaretlendirdiği bir hata olsaydı, o zaman tamam, belki de bir noktanız olurdu. Sınıfımın her üyesini kamuya açmak, sonra yapmaması gereken şeyleri değiştirirken diğer insanları suçlamak gibi olur, değil mi? Ancak, SRP ihlallerini örtmek için belirleyici enjeksiyon kullanan herkes, temel tasarım ilkelerini ya görmezden geliyor ya da tamamen görmezden geliyor. Bunun için suçu IoC konteynerine koymak mantıksız.

    Bu özellikle doğrudur, çünkü zavallı adamın DI'siyle kolayca yapabileceğiniz bir şeydir:

    var myObject 
       = new MyTerriblyLargeObject { DependencyA = new Thing(), DependencyB = new Widget(), Dependency C = new Repository(), ... };
    

    Gerçekten de, bu endişe bir IoC kabının kullanılıp kullanılmadığına tamamen dik görünüyor.

  4. Sınıflarınızın birlikte çalışma şeklini değiştirmek OCP'yi ihlal etmiyor. Öyleyse, tüm bağımlılık inversiyonu OCP ihlalini teşvik ediyor olacaktı. Bu durumda, ikisi de aynı SOLID kısaltmasında olmazdı!

    Ayrıca, a) veya b) noktalarının hiçbiri OCP ile ilgisi olmaya yaklaşmaz. Bunlara OCP ile ilgili nasıl cevap vereceğimi bile bilmiyorum.

    Tahmin edebileceğim tek şey, OCP'nin çalışma zamanında değiştirilmeyen davranışlarla veya bağımlılık yaşam döngüsünün kodun neresinde kontrol edildiği ile ilgili olduğunu düşünmenizdir. Değil. OCP, gereksinimler eklendiğinde veya değiştirildiğinde, mevcut kodu değiştirmek zorunda değildir. Her şey kod yazmakla ilgili , zaten yazdığınız kodların birbirine nasıl yapıştırıldığı ile ilgili değil (elbette, gevşek bağlantı OCP'ye ulaşmanın önemli bir parçasıdır).

Ve söylediğin son bir şey:

Ancak, aynı güveni, el ile yapamadığım şeylere geçici çözümler uygulamak için derlenmiş kodumu değiştiren üçüncü taraf bir araca koyamıyorum.

Evet yapabilirsin . Bu araçların çok sayıda projeye dayanan - diğer üçüncü taraf kütüphanelerden daha beklenmedik bir davranışa yatkın veya eğilimli olduğunu düşünmeniz için kesinlikle hiçbir neden yoktur.

ek

Giriş paragraflarınızın biraz adresleme kullanabileceğini fark ettim. Sardonik olarak, IoC konteynerlerinin bir bağımlılık grafiği oluşturmak için dağınık, çoğaltma eğilimli kodları önlemek için "hiç duymadığımız bazı gizli teknikler kullanmadığını" söylüyorsunuz. Ve oldukça haklısın, yaptıkları aslında programcıların her zaman yaptığımız gibi temel tekniklerle aynı şeyleri ele almak.

Seninle varsayımsal bir senaryo aracılığıyla konuşmama izin ver. Siz, bir programcı olarak, büyük bir uygulamayı bir araya getirdiniz ve giriş noktasında, nesne grafiğinizi oluşturduğunuzda, oldukça karışık kodunuz olduğunu fark ediyorsunuz. Tekrar tekrar tekrar kullanılan çok az sayıda sınıf var ve bunlardan birini her yaptığınızda, altındaki tüm bağımlılık zincirini tekrar kurmak zorundasınız. Ayrıca, her biri için özel kod dışında, bağımlılıkların yaşam döngüsünü açıklamak veya kontrol etmek için anlamlı bir yönteminiz olmadığını görüyorsunuz. Kodunuz yapılandırılmamış ve tekrarlama dolu. Bu, tanıtım paragrafınızda konuştuğunuz karışıklıktır.

İlk önce, biraz tekrar etmeye başladınız - bazı tekrarlanan kodlar yeterince yapılandırılmışsa, onu yardımcı yöntemlere çekersiniz, vb. Ama sonra düşünmeye başlarsınız - bu, belki de genel anlamda ele alabileceğim , bu belirli projeye özgü olmayan ancak gelecekteki tüm projelerinizde size yardımcı olabilecek bir sorun mu?

Demek oturun ve düşünün ve bağımlılıkları çözebilecek bir sınıf olması gerektiğine karar verin. Ve hangi kamu yöntemlerine ihtiyaç duyulacağını siz çizersiniz:

void Bind(Type interfaceType, Type concreteType, bool singleton);
T Resolve<T>();

Bind"nerede yapıcı bir argüman görüyorsanız interfaceType, bir örneğini geçirin concreteType" diyor. Ek singletonparametre, concreteTypeher seferinde aynı vakayı kullanıp kullanmamayı ya da her zaman yeni bir tane yapmamayı söylüyor .

Resolvebasitçe Tdaha önce bağlanmış olan türlerinin argümanlarını bulabildiği herhangi bir kurucu ile kurmaya çalışacağım . Ayrıca bağımlılıkları tamamen aşılması için özyinelemeli olarak da çağırabilir. Bir örneği çözemez, çünkü her şey bağlı değildir, bir istisna atar.

Bunu kendiniz uygulamayı deneyebilirsiniz ve biraz yansıma ve singletondoğru olan bağlamalar için önbelleklemeye ihtiyacınız olduğunu göreceksiniz , ancak kesinlikle sert ve dehşet verici bir şey yok. Ve işiniz bittiğinde - işte , kendi IoC konteynerinizin özüne sahipsiniz! Gerçekten o kadar korkutucu mu? Bu ve Ninject veya StructureMap veya Castle Windsor arasındaki ya da tercih ettiğiniz her şey arasındaki tek fark, bu temel sürümün yeterli olmadığı durumlarda (çok!) Kullanım durumlarını kapsayan daha fazla işlevselliğe sahip olmalarıdır. Ama özünde, sahip olduğun şey bir IoC kabının özü.


Sağol Ben. Gerçekten sadece bir yıl boyunca IOC Containers ile çalıştım ve bunu yapmasam da, çevremdeki eğitmenler ve meslektaşlarım gerçekten mülk enjeksiyonuna (özel dahil) odaklanıyor. Bu delilik ve yaptığım tüm noktaları getiriyor. Ancak diğerleri bu durumda olsalar bile, yapabilecekleri en iyi şey, IOC Konteynerlerinin ilkeleri takip etmek için nasıl çalışması gerektiği hakkında daha fazla bilgi edinmek ve bu ilkeleri kırıcıların kod incelemelerine dikkat çekmek olduğunu düşünüyorum. Ancak ... (devam)
Suamere

En büyük kaygım mutlaka OOP / SOLID İlkeleri'nde listelenmiyor ve bu da kapsamın açıklığı. Hala bir anahtar kelime için pencereyi anlamak için Blok, Yerel, Modül ve Küresel seviye kapsamı atıyoruz. Bir şeyin kapsamın dışına çıktığını veya elden çıkarılacağını belirleyen blokları ve bildirimleri kullanma fikri benim için çok büyük ve bence bu çok temel geliştirme parçasını bir uzantı anahtar kelimesiyle değiştirmek benim için en korkutucu kısmıydı. .
Suamere

Bu yüzden cevabınızı cevap olarak işaretledim, çünkü gerçekten bunun kalbini ele alıyor. Ve okuduğum yöntem, IOC Containers'ın kapakların altında yaptıklarına güvenmek zorunda olduğun, çünkü başkalarının yaptığı gibi. Muhtemel kötüye kullanma açıklıklarına ve örtbas ettiği şıklığa kadar, bir dükkan ve kod incelemeleri için endişelenecek ve iyi gelişme ilkelerini takip etmek için gereken özeni göstermeliler.
Suamere

2
4 ile ilgili olarak, Bağımlılık Enjeksiyonu, SOLID kısaltmasında değildir. 'D' = 'Tamamen alakasız bir kavram olan Bağımlılık İnversiyon Prensibi'.
astreltsov

@astr İyi nokta. "Enjeksiyonu" yerine "ters çevirme" koydum, çünkü ilk önce yazmak istediğim şey buydu. Bağımlılık inversiyonu mutlaka birden fazla somut uygulama anlamına gelmediğinden, bu hala biraz fazla basitleştirmenin bir parçasıdır , ancak anlamın yeterince açık olduğunu düşünüyorum. Uygulamaların kapatılması bir OCP ihlaliyse, polimorfik bir soyutlamaya bağlı olmak tehlikeli olabilir.
Ben Aaronson

27

IOC kapları bu ilkelerin çoğunu bozmaz mı?

Teoride? Hayır. IoC konteynerleri sadece bir araçtır. Tek bir sorumluluğu olan nesnelere, iyi ayrılmış arayüzlere sahip olabilir, davranışlarını bir kez yazıldıktan sonra değiştiremezsiniz, vb.

Uygulamada? Kesinlikle.

Sanırım bir kaç programcılar onlar IoC konteyner kullanmak demek değildir duydum, demek özellikle açık / kapalı prensibi ihlal - Sistemin davranışını değiştirmek için bazı yapılandırma kullanmasına izin vermek. Eskiden XML'in kodlamasıyla ilgili espriler yapıldı, çünkü işlerinin% 90'ı Spring konfigürasyonunu düzeltiyordu. Ve bağımlılıkların gizlenmesinin (kuşkusuz ki tüm IoC konteynerlerinin yapmadığı şekilde) gizlenmesinin kesinlikle birleştiğinden ve yüksek derecede birleştirilmiş ve çok kırılgan bir kod yapmanın hızlı ve kolay bir yoludur.

Buna farklı bir yoldan bakalım. Tek bir temel bağımlılığa sahip çok temel bir sınıfı düşünelim. ActionParametre almayan ve geri dönen bir delege veya functor'a bağlıdır void. Bu sınıfın sorumluluğu nedir? Söyleyemezsin. Bu bağımlılığı açık bir şekilde CleanUpActionadlandırabilirim, ki bunu yapmasını istediğin şeyi yaptığını düşünmeni sağlar. IoC devreye girer girmez her şey olur . Herkes yapılandırmaya gidebilir ve yazılımınızı hemen hemen keyfi şeyler yapmak için değiştirebilir.

“Bunun bir kurucuya Actiongirmesinden farkı nedir?” sen sor. Farklıdır, çünkü yazılım dağıtıldıktan sonra (veya çalışma zamanında!) Yapıcıya geçenleri değiştiremezsiniz. Farklıdır çünkü ünite testleriniz (veya tüketicilerinizin ünite testleri) temsilcinin kurucuya geçtiği senaryoları kapsamıştır.

“Ama bu sahte bir örnek! Eşyalarım davranış değiştirmeye izin vermiyor!” haykırıyorsun. Söylediğim için üzgünüm ama öyle. Enjekte ettiğiniz arayüz sadece veri olmadığı sürece . Arayüzünüz sadece veri değil, çünkü sadece veri olsaydı basit bir nesne oluşturacak ve onu kullanacaktınız. Enjeksiyon noktanızda sanal bir yönteme sahip olduğunuzda, sınıfınızın IoC kullanarak sözleşmesi "Ben her şeyi yapabilirim " dir.

“Bir şeyleri sürmek için komut dosyası kullanmaktan ne kadar farklı olabilir? bazılarınız soruyor. Farklı değil. Bir program tasarımı açısından bakıldığında, hiçbir fark yoktur. Programınızı rasgele kod çalıştırmak için çağırıyorsunuz. Ve elbette, bu uzun yıllar boyunca oyunlarda yapıldı. Tonlarca sistem yönetim aracında yapılır. OOP mi? Pek sayılmaz.

Mevcut her yerde olmaları için mazeret yok. IoC konteynerlerinin tek bir katı amacı vardır - çok sayıda kombinasyonunuz olduğunda bağımlılıklarınızı bir arada yapıştırmak veya bu bağımlılıkları açık hale getirmenin pratik olmayacağı kadar hızlı kayırlar. Yani çok az işletme aslında bu senaryoya uyuyor.


3
Sağ. Ve bir çok dükkan, ürünlerinin gerçekten karmaşık olmadıklarında o kategoriye girecek kadar karmaşık olduğunu iddia edecek. Birçok senaryoda gerçeği olduğu gibi.
Suamere

12
Ancak IoC söylediklerinizin tam tersi. Programın Açık / Yakınlığını kullanır. Eğer kodun kendisini değiştirmek zorunda kalmadan tüm programın davranışını değiştirebilirsiniz.
Öforik

6
@Euphoric - uzatma için açık, değişiklik için kapalı. Tüm programın davranışını değiştirebilirseniz, değişiklik için kapalı değildir, öyle değil mi? IoC yapılandırması hala sizin yazılımınızdır, yine de Java veya C # yerine XML'de olsa da, iş yapmak için sınıflarınız tarafından kullanılan koddur.
Telastyn

4
@Telastyn "Değişiklik için kapalı", bir bütünün davranışını değiştirmek için kodu değiştirmek (değiştirmek) gerekmemesi gerektiği anlamına gelir. Herhangi bir harici konfigürasyonla, onu yeni bir dll'ye yönlendirebilir ve bütün bir değişiklik davranışına sahip olabilirsiniz.
Öforik

12
@Telastyn Açık / kapalı prensibinin söylediği şey bu değil. Aksi halde, parametreleri alan bir yöntem OCP'yi ihlal eder çünkü davranışını farklı parametreler ileterek "değiştirebilirim". Aynı şekilde, OCP sürümünüz altında, DI ile doğrudan bir çelişki içerisinde olacaktır, bu da her ikisinin de SOLID kısaltmasında görünmesini oldukça garip bir hale getirecektir.
Ben Aaronson

14

Bir IoC kabı kullanmak mutlaka OOP / SOLID ilkelerini ihlal ediyor mu? Hayır .

IoC konteynerlerini OOP / SOLID ilkelerini ihlal edecek şekilde kullanabilir misiniz? Evet .

IoC kapları sadece uygulamanızdaki bağımlılıkları yönetmek için kullanılan çerçevelerdir.

Tembel enjeksiyonları, mülk belirleyicileri ve henüz kullanım gereği duymadığımı düşündüğüm diğer bazı özelliklerin size en uygun tasarımdan daha az verebileceğini söylediniz. Bununla birlikte, bu özel özelliklerin kullanımı, IoC kapları uyguladığınız teknolojideki kısıtlamalardan kaynaklanmaktadır.

Örneğin, ASP.NET WebForms, özelliğini başlatmanın mümkün olmadığı için özellik enjeksiyonunu kullanmanız gerekir Page. Bu anlaşılabilir bir durumdur çünkü WebForms hiçbir zaman katı OOP paradigmaları düşünülerek tasarlanmamıştır.

ASP.NET MVC ise, OOP / SOLID dostu yapıcı enjeksiyonunu kullanarak bir IoC kabı kullanmak tamamen mümkün.

Bu senaryoda (yapıcı enjeksiyonunu kullanarak), aşağıdaki nedenlerden dolayı SOLID ilkelerini desteklediğine inanıyorum:

  • Tek Sorumluluk Prensibi - Daha küçük sınıflara sahip olmak, bu sınıfların çok spesifik olmasını ve var olma sebeplerinin bir tane olmasını sağlar. Bir IoC kabı kullanmak onları organize etmeyi çok kolaylaştırır.

  • Açık / Kapalı - Bu, bir IoC kabını kullanmanın gerçekten parladığı, bir sınıfın işlevselliğini farklı bağımlılıkları enjekte ederek genişletebilirsiniz. Enjekte ettiğiniz bağımlılıklara sahip olmak, o sınıfın davranışını değiştirmenizi sağlar. İyi bir örnek, önbellekleme veya günlüğe kaydetme eklemek için bir dekoratör yazarak enjekte ettiğiniz sınıfı değiştirmektir. Uygun bir soyutlama düzeyinde yazılırsa bağımlılıklarınızın uygulamalarını tamamen değiştirebilirsiniz.

  • Liskov Değiştirme Prensibi - Gerçekten alakalı değil

  • Arabirim Ayrıştırma Prensibi - İsterseniz, bir tuz tanesine değen herhangi bir IoC kabının kolayca yapabileceği tek bir zamana birden fazla arayüz atayabilirsiniz.

  • Bağımlılık İnversiyonu - IoC konteynerleri, bağımlılık inversiyonunu kolayca yapmanızı sağlar.

Bir sürü bağımlılık tanımlar, ilişkileri ve kapsamları ilan edersiniz ve patlama patlaması yaparsınız: sihirli bir şekilde kodunuzu veya IL'nizi bir noktada değiştiren ve işlerin çalışmasını sağlayan bir eklenti var. Bu açık veya şeffaf değil.

Hem açık hem de saydamdır, IoC konteynerinize bağımlılıkları nasıl bağlayacağınızı ve nesne ömrünü nasıl yöneteceğinizi söylemeniz gerekir. Bu, kurallara, yapılandırma dosyalarına veya sisteminizin ana uygulamalarına yazılan kodlara göre olabilir.

IOC kapsayıcılarını kullanarak kod yazarken veya okuduğumda, biraz inelegant kodundan kurtulacağını kabul ediyorum.

Sistemleri yönetilebilir hale getirmek için OOP / SOLID'in bütün nedeni budur. Bir IoC kabı kullanmak bu amaç için satır içidir.

Bu sınıfın yazarı “Bir IOC Konteyneri kullanmasaydık, Yapıcı bir düzine parametreye sahip olacaktı! Bu korkunç!” Diyor.

12 bağımlılığı olan bir sınıf muhtemelen hangi bağlamda kullanıyor olursanız olun bir SRP ihlalidir.


2
Mükemmel cevap Ek olarak, tüm büyük IOC konteynerlerinin de OCP'de çok yardımcı olabilecek AOP'yi desteklediğini düşünüyorum. Kesişen endişeler için, AOP genellikle bir Dekoratörden daha OCP dostu bir yoldur.
Ben Aaronson

2
@BenAaronson AOP'nin sınıfa kod koyduğunu düşünürsek, daha fazla OCP dostu demezdim. Derleme / çalışma zamanında bir sınıfı zorla açıp değiştiriyorsunuz.
Doval

1
@Doval Bir sınıfa kod nasıl enjekte ettiğini anlamıyorum. Not: IL-dokuma stilinden ziyade bir ele geçiricinizin bulunduğu Castle DynamicProxy stilinden bahsediyorum. Ancak bir önleyici, temelde, sadece kendini belli bir arayüze bağlamak zorunda kalmaması için bazı yansıma kullanan bir dekoratördür.
Ben Aaronson

"Bağımlılık İnversiyonu - IoC kapları, bağımlılık inversiyonunu kolayca yapmanıza izin verir" - yapmazlar, IoC'ye sahip olsanız da olmasa da faydalı olan bir şeyden yararlanırlar. Diğer ilkelerle aynı.
Den

Gerçekten bir şeyin gerçeğe dayanarak kötü olmadığı, bunun bir çerçeve olduğunu açıklama mantığını anlamıyorum. ServiceLocators da çerçeve olarak yapılır ve kötü olarak kabul edilir :).
ipavlu

5

IOC kapsayıcılarının her ikisi de kırılmıyor ve kodlayıcıların kırılmasına izin vermiyor mu, bir çok OOP / SOLID ilkesi var mı?

staticC # anahtar kelime geliştiriciler OOP / KATI ilkelerin bir sürü kırmak için izin verir ama yine de doğru şartlar geçerli bir araçtır.

IoC kapları iyi yapılandırılmış koda izin verir ve geliştiriciler üzerindeki bilişsel yükü azaltır. Aşağıdaki SOLID ilkelerini daha kolay hale getirmek için bir IoC kabı kullanılabilir. Elbette kötüye kullanılabilir, ancak kötüye kullanılabilecek herhangi bir aracın kullanımını dışlarsak, programlamayı tamamen bırakmak zorunda kalacağız.

Bu nedenle, bu rant zayıf yazılmış kod hakkında bazı geçerli noktaları ortaya çıkarsa da, bu tam olarak bir soru değil ve tam olarak kullanışlı değil.


Kapsamı, tembelliği ve erişilebilirliği yönetmek için derlenmiş kodu OOP / SOLID'i kıran şeyleri yapmak için değiştiren, ancak bu uygulamayı güzel bir çerçeve altında gizleyen IOC Containers'ın anlayışı benim. Ama evet, ayrıca yanlış kullanım için diğer kapıları açar. Soruma en iyi cevap, kendi araştırmamı ekleyen veya olumsuzlayan IOC Konteynerlerinin nasıl uygulandığına dair bir açıklama olacaktır.
Suamere

2
@ Suamere - Çok geniş bir IOC tanımı kullanıyor olabilirsiniz. Kullandığım derlenmiş kodu değiştirmiyor. Derlenmiş kodu değiştiren başka birçok IOC dışı araç var. Belki de başlığınız şöyle olmalı: "Derlenmiş kodun değiştirilmesi ...".
Cerad

@Samamere IoC ile pek tecrübeli değilim, fakat IoC değiştirilmiş derleme kodunu hiç duymadım. Lütfen hangi platformlardan / dillerden / çerçevelerden bahsettiğiniz hakkında bilgi verir misiniz?
Öforik

1
"Aşağıdaki SOLID ilkelerini daha kolay hale getirmek için bir IoC kabı kullanılabilir." - Lütfen detaylandırır mısınız? Her prensipte ne kadar özel olarak yardımcı olduğunu açıklamak yardımcı olacaktır. Ve elbette bir şeyden yararlanmak, bir şeyin olmasına yardımcı olmakla aynı şey değildir (örneğin DI).
Den

1
@Euphoric Suamere'nin konuştuğu .net framework'lerini bilmiyorum, ancak Spring kesinlikle başlık altında kod değişikliği yapıyor. En belirgin örnek, yönteme dayalı enjeksiyon desteği (sınıfında yönettiği bir bağımlılığı döndürmek için soyut bir yöntemi geçersiz kıldığı). Ayrıca, ek davranışlar sağlamak için kodunuzu sarmak amacıyla otomatik olarak oluşturulan proxy'lerden geniş ölçüde yararlanır (örneğin, işlemleri otomatik olarak yönetmek için). Bununla birlikte, bunun birçoğu, DI çerçevesi olarak rolüyle ilgili değildir.
Jules

3

Sorunuzda birden fazla hata ve yanlış anlamalar görüyorum. Bunlardan ilki, mülk / alan enjeksiyonu, yapıcı enjeksiyonu ve servis bulucu arasındaki farkın eksik olmasıdır. Bazı şeyleri yapmanın doğru yolu olan tartışmalar (örneğin flamewars) olmuştur. Sorunuzda, sadece mülk enjeksiyonunu üstlendiğiniz ve yapıcı enjeksiyonunu göz ardı ettiğiniz görülüyor.

İkincisi, IoC konteynerlerinin bir şekilde kodunuzun tasarımını etkilediğini varsayıyor olmanız. IoC kullanıyorsanız, kodların tasarımını değiştirmek gerekmez veya en azından gerekli olmamalıdır. Birçok yapıcı içeren sınıflarla ilgili problemleriniz IoC'nin kodunuzla (muhtemelen SRP'yi kıran bir sınıf) gerçek problemleri gizlemesidir ve gizli bağımlılıklar, insanların mülk enjeksiyonunu ve servis bulucu kullanımını engellemelerinin sebeplerinden biridir.

Açık-kapalı prensipte sorunun bu duruma nereden geldiğini anlamıyorum, bu yüzden bu konuda yorum yapmayacağım. Ancak SOLID'in bir bölümünü özlüyorsunuz, bunun üzerinde büyük etkisi var: Bağımlılık İnversiyon ilkesi. DIP'yi izlerseniz, bir bağımlılığın tersine çevrilmesinin bir sınıf örneği oluşturulduğunda uygulamasının çözülmesi gereken bir soyutlama getirdiğini göreceksiniz. Bu yaklaşımla, inşaatta düzgün çalışması için birden fazla arayüzün gerçekleştirilmesini ve sağlanmasını gerektiren çok sayıda sınıfla karşılaşacaksınız. O zaman bu bağımlılıkları elle sağlamak isteseydiniz, çok fazla ek iş yapmanız gerekirdi. IoC kapları bu işi kolaylaştırır ve hatta programı yeniden derlemenize gerek kalmadan değiştirmenize izin verir.

Yani, sorunuzun cevabı hayır. IoC konteynerleri, OOP tasarım ilkelerini bozmaz. Aksine, aşağıdaki SOLID ilkelerinin (özellikle Bağımlılık-İnversiyon ilkesi) neden olduğu sorunları çözerler.


Son zamanlarda önemsiz olmayan bir projeye IoC (Autofac) uygulama denendi. Dil dışı yapılarla benzer bir iş yapmak zorunda olduğumu farkettim (new () vs API): arayüzlere neyin çözüleceğini ve somut sınıflara neyin çözüleceğini, neyin bir örnek olması gerektiğini ve tekil olması gerektiğini belirleyerek, özellik enjeksiyonunun dairesel bir bağımlılığı hafifletmek için doğru çalıştığından emin olmak. Vazgeçmeye karar verdim. Ancak ASP MVC'deki Kontrolörler ile iyi çalışır.
Den

@Den Projeniz akılda bağımlılık inversiyonu ile açıkça tasarlanmadı. Ve hiçbir yerde IoC kullanmanın önemsiz olmadığını söyledim.
Öforik

Aslında, bu şey - Ben başından beri Bağımlılık Inversion kullanıyorum. Bunun ötesindeki tasarımı etkileyen IoC benim en büyük endişem. Öyleyse neden IoC'yi daha basit hale getirmek için her yerde arayüzleri kullanayım? Ayrıca soru hakkındaki en iyi yoruma bakın.
Den

@ Teknik olarak arayüzleri kullanmaya "ihtiyaç duymayacaksınız". Arabirimler, birim testi için alay etmeye yardımcı olur. Sanal olarak alay etmek için ihtiyacınız olan şeyleri de işaretleyebilirsiniz.
Fred
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.