'Yeni' anahtar kelimeyi ne zaman kullanmalı ve kullanmamalısınız?


15

Misko Hevery tarafından verilen Birim Testi ile ilgili bir Google Tech Talk sunumu izledim ve newanahtar kelimeyi iş mantığı kodunda kullanmaktan kaçındığını söyledi .

Bir program yazdım newve orada burada anahtar kelimeyi kullandım , ancak çoğunlukla veri tutan nesneleri (örn. Herhangi bir işlevi veya yöntemi yoktu) somutlaştırmak içindi.

Merak ediyorum, programım için yeni anahtar kelimeyi kullandığımda yanlış bir şey mi yaptım? Ve bu 'kuralı' nereden kırabiliriz?


2
Programlama dili ile ilgili bir etiket ekleyebilir misiniz? Yeni birçok dilde mevcuttur (C ++, Java, Ruby birkaç isim) ve farklı semantiğe sahiptir.
sakisk

Yanıtlar:


16

Bu, zor ve hızlı kuraldan daha fazla rehberliktir.

Üretim kodunuzda "yeni" kullanarak, sınıfınızı ortak çalışanlarıyla birleştiriyorsunuz. Birisi başka bir ortak çalışan kullanmak istiyorsa, örneğin birim testi için bir tür sahte ortak çalışan kullanmak isterse, yapamazlar - çünkü ortak çalışan iş mantığınızda oluşturulur.

Tabii ki, birisinin bu yeni nesneleri yaratması gerekir, ancak bu genellikle en iyi iki yerden birine bırakılır: Spring gibi bir bağımlılık enjeksiyon çerçevesi veya başka hangi sınıfta iş mantığı sınıfınızı oluşturuyorsa, kurucu aracılığıyla enjekte edilir.

Tabii ki, bunu çok ileriye götürebilirsiniz. Yeni bir ArrayList döndürmek istiyorsanız, muhtemelen tamamsınız demektir - özellikle de bu değişmez bir Liste olacaksa.

Kendinize sormanız gereken ana soru, "bu tür nesneler oluşturmak için bu kod parçasının ana sorumluluğudur ya da bu sadece makul bir şekilde başka bir yere taşıyabileceğim bir uygulama detayı mıdır?"


1
Değişmez bir liste olmasını istiyorsanız, kullanmalısınız Collections.unmodifiableList. Ama ne demek istediğini biliyorum :)
MatrixFrog

Evet, ancak bir şekilde değiştirilemez olmaya dönüştürdüğünüz orijinal listeyi oluşturmanız gerekir ...
Bill Michell

5

Bu sorunun en önemli noktası şudur: Merak ediyorum, programım için yeni anahtar kelimeyi kullandığımda yanlış bir şey mi yaptım? Ve bu 'kuralı' nereden kırabiliriz?

Kodunuz için etkili birim testleri yazabiliyorsanız, yanlış bir şey yapmadınız. Eğer newkodunuzu test etmeyi zorlaştırır veya imkansız hale getirirseniz, yeni kod kullanımınızı yeniden değerlendirmelisiniz. Bu analizi diğer sınıflarla etkileşime genişletebilirsiniz, ancak katı birim testleri yazma yeteneği genellikle yeterince iyi bir proxy'dir.


5

Kısacası, "new" ifadesini her kullandığınızda, bu kodu içeren sınıfı yaratılan nesneye sıkıca bağlarsınız; bu nesnelerden birini somutlaştırmak için, somutlaştırmayı yapan sınıf somutlaştırılmış somut sınıfı bilmelidir. Dolayısıyla, "yeni" kullanırken, somutlaştırmayı yerleştirdiğiniz sınıfın bu bilginin ikamet etmesi için "iyi" bir yer olup olmadığını düşünmelisiniz ve eğer bu formda somutlaştırılan nesne değişecekti.

Başka bir somut sınıf bilgisi olan bir nesne olan sıkı bağlantıdan her zaman kaçınılmaz; bir düzeyde, SOMEWHERE, bir şey, başka bir şeyden başka bir yerden bir kopyası verilerek nesne ile ilgilense bile, bu nesnenin nasıl oluşturulacağını bilmek zorundadır. Ancak, yaratılan sınıf değiştiğinde, söz konusu sınıfın somut uygulamasını bilen herhangi bir sınıf, söz konusu sınıfın değişiklikleriyle doğru bir şekilde ilgilenmek üzere güncellenmelidir.

Her zaman sormanız gereken soru şudur: "Bu sınıfa bu sınıfın nasıl oluşturulacağını bilmek uygulamayı korurken bir yükümlülük haline gelecek mi?" Her iki önemli tasarım metodolojisi (SOLID ve GRASP) genellikle farklı nedenlerle "evet" yanıtı verir. Bununla birlikte, bunlar sadece metodolojilerdir ve her ikisinin de benzersiz programınızın bilgisine dayanarak formüle edilmedikleri aşırı sınırlamaları vardır. Bu nedenle, sadece dikkatle yanabilirler ve herhangi bir sıkı bağlantı noktasının, açıkça bu noktanın her iki tarafında veya her iki tarafında değişiklik yapma ile ilgili bir soruna neden olacağını varsayabilirler. Üç şeyi bilerek nihai bir karar vermelisiniz; teorik en iyi uygulama (her şeyi gevşek bir şekilde birleştirmek çünkü her şey değişebilir); teorik en iyi uygulamayı uygulama maliyeti (bir tür değişikliği diğerini engellerken bir tür değişikliği kolaylaştıracak birkaç yeni soyutlama katmanı içerebilir); ve tahmin ettiğiniz değişiklik türünün gerçek dünya olasılığı hiç gerekmeyecek.

Bazı genel yönergeler:

  • Derlenmiş kod kitaplıkları arasında sıkı bağlantıdan kaçının. DLL'ler (veya bir EXE ve DLL'leri) arasındaki arabirim, sıkı bağlantının bir dezavantaj sunacağı ana yerdir. DLL X'te A sınıfında bir değişiklik yaparsanız ve ana EXE'deki B sınıfı A sınıfını bilirse, her iki ikili dosyayı yeniden derlemeniz ve serbest bırakmanız gerekir. Tek bir ikili sistem içinde, daha sıkı bağlantıya genel olarak daha izin verilir, çünkü tüm ikili dosyalar yine de herhangi bir değişiklik için yeniden oluşturulmalıdır. Bazen, birden fazla ikili dosyayı yeniden oluşturmak kaçınılmazdır, ancak kodunuzu, özellikle bant genişliğinin yüksek olduğu durumlarda (mobil uygulamaları dağıtmak gibi; yeni bir DLL'i yükseltme sırasında itmek çok daha ucuzdur) mümkün olan yerlerde kaçınabileceğiniz şekilde yapılandırmalısınız. programın tamamını zorlamaktan çok).

  • Programınızın ana "mantık merkezleri" arasında sıkı bağlantıdan kaçının. İyi yapılandırılmış bir programı yatay ve dikey dilimlerden oluşan olarak düşünebilirsiniz. Yatay dilimler, UI, Controller, Domain, DAO, Data gibi geleneksel uygulama katmanları olabilir; dikey dilimler tek tek pencereler veya görünümler için veya tek tek "kullanıcı hikayeleri" için tanımlanabilir (bazı temel türlerde yeni bir kayıt oluşturmak gibi). İyi yapılandırılmış bir sistemde yukarı, aşağı, sola veya sağa hareket eden bir arama yaparken, genellikle bu aramayı soyutlamanız gerekir. Örneğin, validasyonun veri alması gerektiğinde, doğrudan DB'ye erişimi olmamalı, ancak bunu nasıl yapacağını bilen gerçek nesne tarafından desteklenen veri alımı için bir arayüze çağrı yapmalıdır. Bazı kullanıcı arayüzü kontrolünün başka bir pencereyi içeren gelişmiş mantık gerçekleştirmesi gerektiğinde, bir olay ve / veya geri arama yoluyla bu mantığın tetiklenmesini özetlemelidir; sonuç olarak ne yapılacağını bilmek zorunda kalmaz ve onu tetikleyen kontrolü değiştirmeden ne yapılacağını değiştirmenize izin vermez.

  • Her durumda, bir değişikliğin ne kadar kolay veya zor olacağını ve söz konusu değişikliğin ne kadar muhtemel olacağını düşünün. Oluşturduğunuz bir nesne yalnızca tek bir yerden kullanılıyorsa ve değiştirmeyi öngörmüyorsanız, o zaman sıkı bağlantıya genellikle daha izin verilir ve hatta bu durumda gevşek bağlantıya göre daha üstün olabilir. Gevşek bağlantı, bir bağımlılığın uygulanmasının değişmesi gerektiğinde bağımlı nesnelerde değişiklik yapılmasını önleyen ekstra bir katman olan soyutlama gerektirir. Ancak, arabirimin kendisinin değişmesi gerekiyorsa (yeni bir yöntem çağrısı ekleme veya varolan bir yöntem çağrısına parametre ekleme), bir arabirim aslında değişikliği yapmak için gereken iş miktarını artırır. Tasarımı etkileyen farklı tür değişiklik olasılığını tartmanız gerekir,


3

Yalnızca veri barındıran nesneler veya DTO'lar (veri aktarım nesneleri) iyidir, gün boyunca bunları oluşturur. Kaçınmak istediğiniz neweylemler yapan sınıflar üzerindeyse, tüketen sınıfların bunun yerine , bu mantığı çağırabilecekleri ve tüketebilecekleri arayüze karşı programlamasını istersiniz , ancak aslında mantığı içeren sınıfların örneklerini oluşturmaktan sorumlu değildir. . Bu eylem gerçekleştiren veya mantık içeren sınıflar bağımlılıklardır. Misko'nun konuşması size bu bağımlılıkları enjekte etmek ve başka bir varlığın onları gerçekten oluşturmaktan sorumlu olmasına izin vermek içindir.


2

Diğerleri bu noktadan daha önce bahsetmişlerdi, ancak bunu Bob Amca'nın (Bob Martin) Temiz Kodundan alıntılamak istediler, çünkü kavramı anlamayı kolaylaştırabilir:

" Yapıyı kullanımdan ayırmak için güçlü bir mekanizma, Bağımlılığın Enjeksiyonu ( DIC), bağımlılık yönetimine Kontrolün İnversiyonu (IoC) uygulamasıdır. Kontrolün ters çevrilmesi, ikincil sorumlulukları bir nesneden amaca adanmış diğer nesnelere taşır, böylece Tek sorumluluk Prensibi . bağımlılık yönetimi bağlamında, bir nesne bağımlılıklarını kendisini başlatmasını sorumluluğunu almak gerekir. bunun yerine, bu suretle kontrol tersini, başka bir "yetkili" mekanizmasına bu sorumluluğu geçmelidir. kurulum küresel bir endişe olduğundan, bu yetkili mekanizma genellikle "ana" rutin veya özel amaçlı bir konteyner "olacaktır.

Bu kurala uymak her zaman iyi bir fikir olduğunu düşünüyorum . Diğerleri daha önemli bir IMO'dan bahsetti -> sınıfınızı bağımlılıklarından (ortak çalışanlar) ayırır. İkinci neden, sınıflarınızı daha küçük ve ters, anlaşılması ve hatta diğer bağlamlarda yeniden kullanmasıdır.

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.