CodeGym/Java Kursu/Modül 3/Bağımlılık Tersine Çevirme

Bağımlılık Tersine Çevirme

Mevcut

9.1 Bağımlılık Tersine Çevirme

new Thread().start()Hatırlayın, bir keresinde bir sunucu uygulamasında sadece ? üzerinden akış oluşturamayacağınızı söylemiştik. Yalnızca kapsayıcı iş parçacığı oluşturmalıdır. Şimdi bu fikri daha da geliştireceğiz.

Ayrıca tüm nesneler yalnızca kapsayıcı tarafından oluşturulmalıdır . Tabii ki, tüm nesnelerden değil, sözde iş nesnelerinden bahsediyoruz. Ayrıca genellikle çöp kutuları olarak da adlandırılırlar. Bu yaklaşımın ayakları, sınıflardan kurtulmayı ve arayüzlere geçmeyi gerektiren SOLID'in beşinci ilkesinden kaynaklanmaktadır:

  • Üst düzey modüller, alt düzey modüllere bağlı olmamalıdır. Hem bunlar hem de diğerleri soyutlamalara bağlı olmalıdır.
  • Soyutlamalar ayrıntılara bağlı olmamalıdır. Uygulama, soyutlamaya bağlı olmalıdır.

Modüller, belirli uygulamalara referanslar içermemeli ve aralarındaki tüm bağımlılıklar ve etkileşimler yalnızca soyutlamalar (yani arayüzler) temelinde oluşturulmalıdır. Bu kuralın özü tek bir cümleyle yazılabilir: tüm bağımlılıklar arayüzler biçiminde olmalıdır .

Temel doğasına ve görünüşteki basitliğine rağmen, bu kural en sık ihlal edilir. Yani, programın/modülün kodunda new operatörünü her kullandığımızda ve belirli bir türde yeni bir nesne oluşturduğumuzda, böylece arayüze bağlı olmak yerine, uygulamaya bağımlılık oluşur.

Bunun önlenemeyeceği ve nesnelerin bir yerde yaratılması gerektiği açıktır. Ancak, en azından, bunun yapıldığı ve hangi sınıfların açıkça belirtildiği yerlerin sayısını en aza indirmeniz ve bu tür yerleri program kodu boyunca dağılmaması için yerelleştirmeniz ve izole etmeniz gerekir.

Çok iyi bir çözüm, fabrikalar, hizmet bulucuları, IoC konteynerleri gibi özel nesneler ve modüller içinde yeni nesnelerin oluşturulmasına konsantre olma çılgın fikridir.

Bir anlamda, böyle bir karar, "Bir yazılım sistemi birçok alternatifi desteklemesi gerektiğinde, bunların tam listesi sistemin yalnızca bir modülü tarafından bilinmelidir" diyen Tek Seçim İlkesini takip eder .

Bu nedenle, gelecekte yeni seçenekler (veya düşündüğümüz yeni nesneler oluşturma durumunda olduğu gibi yeni uygulamalar) eklemek gerekirse, yalnızca bu bilgiyi içeren modülü ve diğer tüm modülleri güncellemek yeterli olacaktır. etkilenmeyecek ve her zamanki gibi çalışmalarına devam edebilecektir.

örnek 1

new ArrayList gibi bir şey yazmak yerine, List.new()JDK'nin size bir yaprağın doğru uygulamasını sağlaması mantıklı olacaktır : ArrayList, LinkedList ve hatta ConcurrentList.

Örneğin, derleyici, nesneye farklı evrelerden gelen çağrılar olduğunu görür ve oraya evre güvenli bir uygulama koyar. Veya sayfanın ortasında çok fazla ekleme varsa, uygulama LinkedList'e dayalı olacaktır.

Örnek 2

Bu, örneğin türlerde zaten oldu. Bir koleksiyonu sıralamak için en son ne zaman bir sıralama algoritması yazdınız? Bunun yerine, artık herkes yöntemini kullanıyor Collections.sort()ve koleksiyonun öğeleri Comparable arabirimini (karşılaştırılabilir) desteklemelidir.

sort()Yönteme 10'dan az öğeden oluşan bir koleksiyon iletirseniz, onu Quicksort ile değil, bir bubble sort (Bubble sort) ile sıralamak oldukça mümkündür .

Örnek 3

Derleyici zaten dizeleri nasıl birleştirdiğinizi izliyor ve kodunuzu StringBuilder.append().

9.2 Uygulamada bağımlılık tersine çevirme

Şimdi en ilginç olanı: teori ve pratiği nasıl birleştirebileceğimizi düşünelim. Modüller "bağımlılıklarını" nasıl doğru bir şekilde oluşturup alabilir ve Bağımlılık Tersine Çevirmeyi ihlal etmez?

Bunu yapmak için, bir modül tasarlarken aşağıdakilere kendiniz karar vermelisiniz:

  • modül ne yapar, hangi işlevi yerine getirir;
  • o zaman modülün çevresinden ihtiyacı var, yani hangi nesnelerle / modüllerle uğraşması gerekecek;
  • Ve nasıl alacak?

Dependency Inversion ilkelerine uymak için modülünüzün hangi dış nesneleri kullanacağına ve bunlara nasıl referans alacağına mutlaka karar vermelisiniz.

Ve işte aşağıdaki seçenekler:

  • modülün kendisi nesneleri oluşturur;
  • modül nesneleri kaptan alır;
  • modülün nesnelerin nereden geldiği hakkında hiçbir fikri yoktur.

Sorun şu ki, bir nesne oluşturmak için belirli bir türden bir kurucu çağırmanız gerekiyor ve sonuç olarak modül arayüze değil, belirli uygulamaya bağlı olacaktır. Ancak, modül kodunda nesnelerin açıkça oluşturulmasını istemiyorsak, Fabrika Yöntemi modelini kullanabiliriz .

"Sonuç olarak, yeni aracılığıyla bir nesneyi doğrudan başlatmak yerine, istemci sınıfına nesneler oluşturmak için bazı arabirimler sağlıyoruz. Böyle bir arabirim her zaman doğru tasarımla geçersiz kılınabileceğinden, düşük seviyeli modülleri kullanırken biraz esneklik elde ediyoruz. üst düzey modüllerde" .

İlgili nesnelerin gruplarını veya ailelerini oluşturmanın gerekli olduğu durumlarda, Fabrika Yöntemi yerine Soyut fabrika kullanılır .

9.3 Servis Bulucuyu Kullanma

Modül, gerekli nesneleri zaten sahip olandan alır. Sistemin, modüllerin nesnelerini "koyabilecekleri" ve depodan nesneleri "alabilecekleri" bazı nesneler havuzuna sahip olduğu varsayılmaktadır.

Bu yaklaşım, ana fikri , programın gerekli olabilecek tüm bağımlılıkları (hizmetleri) nasıl alacağını bilen bir nesneye sahip olduğu Servis Bulucu modeli tarafından uygulanır .

Fabrikalardan temel fark, Service Locator'ın nesneler oluşturmaması, ancak aslında zaten örneklenmiş nesneler içermesidir (veya bunları nereden / nasıl alacağını bilir ve oluşturursa, o zaman yalnızca ilk çağrıda bir kez). Her çağrıda fabrika, tam mülkiyetine sahip olduğunuz ve onunla istediğinizi yapabileceğiniz yeni bir nesne oluşturur.

Önemli ! Hizmet bulucu, halihazırda var olan aynı nesnelere referanslar üretir . Bu nedenle, Hizmet Bulucu tarafından yayınlanan nesneler konusunda çok dikkatli olmanız gerekir, çünkü bunları sizinle aynı anda başka biri kullanabilir.

Servis Bulucu'daki nesneler, doğrudan yapılandırma dosyası aracılığıyla ve aslında programcı için uygun olan herhangi bir şekilde eklenebilir. Hizmet Bulucu'nun kendisi, bir dizi statik yöntem, tekil öğe veya arabirim içeren statik bir sınıf olabilir ve gerekli sınıflara bir yapıcı veya yöntem aracılığıyla iletilebilir.

Servis Bulucuya bazen anti-kalıp denir ve önerilmez (çünkü örtülü bağlantılar oluşturur ve yalnızca iyi tasarım görünümü verir). Mark Seaman'dan daha fazlasını okuyabilirsiniz:

9.4 Bağımlılık Enjeksiyonu

Modül, "madencilik" bağımlılıklarını hiç umursamıyor. Yalnızca çalışması için neye ihtiyacı olduğunu belirler ve gerekli tüm bağımlılıklar dışarıdan başka biri tarafından sağlanır (tanıtılır).

Buna - Bağımlılık Enjeksiyonu denir. Tipik olarak, gerekli bağımlılıklar, yapıcı parametreleri (Yapıcı Enjeksiyonu) veya sınıf yöntemleri (Setter enjeksiyonu) aracılığıyla iletilir.

Bu yaklaşım, bağımlılık oluşturma sürecini tersine çevirir - modülün kendisi yerine, bağımlılıkların oluşturulması dışarıdan biri tarafından kontrol edilir. Nesnelerin aktif yayıcısından gelen modül pasif hale gelir - yaratan o değildir, diğerleri onun için yaratır.

Yöndeki bu değişikliğe, Kontrolün Tersine Dönmesi veya Hollywood Prensibi denir - "Bizi arama, biz seni ararız."

Bu , modüllere en fazla özerkliği sağlayan en esnek çözümdür . "Tek Sorumluluk İlkesini" yalnızca onun tam olarak uyguladığını söyleyebiliriz - modül tamamen işini iyi yapmaya odaklanmalı ve başka hiçbir şey için endişelenmemelidir.

Modüle çalışması için gerekli olan her şeyi sağlamak ayrı bir görevdir ve uygun "uzman" tarafından ele alınmalıdır (bağımlılıkların yönetiminden ve uygulanmasından genellikle belirli bir kapsayıcı, bir IoC kabı sorumludur).

Aslında burada her şey hayattaki gibidir: iyi organize edilmiş bir şirkette, programcılar programı ve masalar, bilgisayarlar ve iş için ihtiyaç duydukları her şey ofis yöneticisi tarafından satın alınır ve sağlanır. Veya, bir kurucu olarak programın metaforunu kullanırsanız, modül kabloları düşünmemelidir, kurucunun montajında ​​​​parçaların kendisi değil, başka biri yer alır.

Modüller arasındaki bağımlılıkları tanımlamak için arayüz kullanımının (Bağımlılık Tersine Çevirme) + bu bağımlılıkların doğru şekilde oluşturulması ve enjeksiyonunun (öncelikle Dependency Injection) ayrıştırma için anahtar teknikler olduğunu söylemek abartı olmaz .

Kodun gevşek bağlantısının, esnekliğinin, değişikliklere karşı direncinin, yeniden kullanımının ve diğer tüm tekniklerin çok az anlam ifade ettiği temel olarak hizmet ederler. Bu, gevşek bağlantının ve iyi mimarinin temelidir.

Kontrolü Tersine Çevirme ilkesi (Bağımlılık Enjeksiyonu ve Hizmet Bulucu ile birlikte) Martin Fowler tarafından ayrıntılı olarak ele alınmıştır. Her iki makalesinin de çevirisi var: "Inversion of Control Containers and the Dependency Injection pattern" ve "Inversion of Control" .

Yorumlar
  • Popüler
  • Yeni
  • Eskimiş
Yorum bırakmak için giriş yapmalısınız
Bu sayfada henüz yorum yok