İyi mi kötü mü? Alıcıdaki nesneleri başlatma


167

Garip bir alışkanlığım var ... en azından iş arkadaşımın bilgisine göre. Birlikte küçük bir proje üzerinde çalışıyoruz. Sınıfları yazma şeklim (basitleştirilmiş örnek):

[Serializable()]
public class Foo
{
    public Foo()
    { }

    private Bar _bar;

    public Bar Bar
    {
        get
        {
            if (_bar == null)
                _bar = new Bar();

            return _bar;
        }
        set { _bar = value; }
    }
}

Yani, temelde, herhangi bir alanı yalnızca bir alıcı çağrıldığında ve alan hala boş olduğunda başlattım. Bunun, hiçbir yerde kullanılmayan özellikleri başlatmadan aşırı yüklenmeyi azaltacağını düşündüm.

ETA: Bunu yapmamın nedeni, sınıfımın başka bir sınıfın örneğini döndüren birkaç özelliğe sahip olması ve bunun da daha fazla sınıf içeren özelliklere sahip olmasıdır. Üst sınıf için yapıcı çağrıldığında, her zaman gerekli olmadığında, tüm bu sınıflar için tüm yapıcılar çağrılır.

Bu uygulamaya karşı kişisel tercih dışında herhangi bir itiraz var mı?

GÜNCELLEME: Bu soru ile ilgili birçok farklı görüşü dikkate aldım ve kabul edilen cevabımın yanında olacağım. Ancak, şimdi kavramı daha iyi anladım ve ne zaman kullanacağım ve ne zaman kullanacağım konusunda karar verebiliyorum.

Eksileri:

  • İş parçacığı güvenlik sorunları
  • Geçirilen değer null olduğunda "ayarlayıcı" isteğine uymamak
  • Mikro optimizasyonlar
  • İstisna yönetimi bir kurucuda yapılmalıdır
  • Sınıf kodunda null olup olmadığını kontrol etmeniz gerekiyor

Artıları:

  • Mikro optimizasyonlar
  • Özellikler hiçbir zaman sıfır döndürmez
  • "Ağır" nesneleri geciktirme veya yüklemekten kaçınma

Eksilerini çoğu benim mevcut kitaplık için geçerli değildir, ancak "mikro-optimizasyon" aslında bir şey hiç optimize olup olmadığını görmek için test etmek gerekir.

SON GÜNCELLEME:

Tamam, cevabımı değiştirdim. Orijinal sorum bunun iyi bir alışkanlık olup olmadığıydı. Ve şimdi bunun olmadığına ikna oldum. Belki hala geçerli kodumun bazı bölümlerinde kullanacağım, ancak koşulsuz ve kesinlikle her zaman değil. Bu yüzden alışkanlığımı kaybedeceğim ve kullanmadan önce düşüneceğim. Herkese teşekkürler!


14
Bu tembel yük deseni, tam olarak size harika bir fayda sağlamaz, ancak yine de iyi bir şeydir.
Machinarius

28
Tembel örnekleme, ölçülebilir bir performans etkiniz varsa veya bu üyeler nadiren kullanılır ve çok büyük miktarda bellek tüketiyorsa veya bunları örneklemek uzun zaman alıyorsa ve yalnızca istek üzerine yapmak istiyorsanız mantıklıdır. Her halükarda, iplik güvenliği sorunlarını (mevcut kodunuz değil ) dikkate aldığınızdan ve sağlanan Lazy <T> sınıfını kullanmayı düşünün .
Chris Sinclair


7
@PLB tekil bir desen değildir.
Colin Mackay

30
Kimse bu kod ile ciddi bir hata bahsetmedi şaşırdım. Dışarıdan ayarlayabileceğim bir kamu mülkünüz var. Bunu NULL olarak ayarlarsam, her zaman yeni bir nesne oluşturur ve ayarlayıcı erişimimi yok sayarsınız. Bu çok ciddi bir hata olabilir. Özel mülkler için, bu okie olabilir. Şahsen, böyle erken optimizasyonları yapmak istemiyorum. Hiçbir ek yarar olmadan karmaşıklık ekler.
SolutionYogi

Yanıtlar:


170

Burada "tembel başlatma" nın saf bir uygulaması var.

Kısa cevap:

Tembel başlatmayı koşulsuz olarak kullanmak iyi bir fikir değildir. Yerleri var ama bu çözümün etkilerini dikkate almak gerekiyor.

Arka plan ve açıklama:

Somut uygulama:
Önce somut örneğinize ve onun uygulanmasının neden saf olduğunu düşündüğüme bakalım:

  1. En Az Sürpriz İlkesini (POLS) ihlal ediyor . Bir özelliğe bir değer atandığında, bu değerin döndürülmesi beklenir. Uygulamanızda durum böyle değildir null:

    foo.Bar = null;
    Assert.Null(foo.Bar); // This will fail
    
  2. Oldukça bazı iş parçacığı sorunları ortaya çıkarıyor: foo.BarFarklı iş parçacıklarından iki arayan potansiyel olarak iki farklı örnek alabilir Barve bunlardan biri Fooörnekle bağlantısız olacaktır . Bu Barörnekte yapılan değişiklikler sessizce kaybolur.
    Bu, başka bir POLS ihlali vakasıdır. Bir özelliğin yalnızca depolanan değerine erişildiğinde, iş parçacığının güvenli olması beklenir. Sınıfın, mülkünüzün alıcısı da dahil olmak üzere, iş parçacığı açısından güvenli olmadığını iddia edebilirsiniz, ancak normal durum olmadığı için bunu düzgün bir şekilde belgelemeniz gerekir. Ayrıca, kısa bir süre için göreceğimiz gibi bu konunun tanıtımı gereksizdir.

Genel olarak:
Şimdi genel olarak tembel başlatmaya bakmanın zamanı geldi:
Tembel başlatma genellikle inşa edilmesi uzun süren veya tamamen inşa edildiğinde çok fazla bellek alan nesnelerin yapımını geciktirmek için kullanılır .
Bu tembel başlatma kullanmanın çok geçerli bir nedenidir.

Bununla birlikte, bu tür özellikler normalde yukarıda belirtilen ilk sorundan kurtulan ayarlayıcılara sahip değildir.
Ayrıca, Lazy<T>ikinci sayıyı önlemek için , iş parçacığı açısından güvenli bir uygulama kullanılabilir .

Tembel bir mülkün uygulanmasında bu iki noktayı düşünürken bile, aşağıdaki noktalar bu modelin genel problemleridir:

  1. Nesnenin inşası başarısız olabilir ve bir mülk alıcısından istisnaya neden olabilir. Bu yine bir başka POLS ihlalidir ve bundan kaçınılmalıdır. "Sınıf Kitaplıkları Geliştirmek için Tasarım Yönergeleri" ndeki mülkler bölümü bile mülk sahiplerinin istisnalar atmaması gerektiğini açıkça belirtmektedir:

    Mülk sahiplerinden istisna atmaktan kaçının.

    Mülk sahipleri, herhangi bir önkoşul olmaksızın basit operasyonlar olmalıdır. Alıcı bir istisna oluşturabilirse, özelliği bir yöntem olarak yeniden tasarlamayı düşünün.

  2. Derleyici tarafından otomatik optimizasyonlar zarar görür, yani satır içi ve dal tahmini. Ayrıntılı bir açıklama için lütfen Bill K'nin cevabına bakınız .

Bu noktaların sonucu şudur:
Tembel olarak uygulanan her bir mülk için bu noktaları dikkate almalısınız.
Bu, duruma göre bir karar olduğu ve en iyi genel uygulama olarak alınamayacağı anlamına gelir.

Bu modelin yeri vardır, ancak sınıfları uygularken genel olarak en iyi uygulama değildir. Yukarıda belirtilen nedenlerden dolayı koşulsuz kullanılmamalıdır .


Bu bölümde, tembel başlatmayı koşulsuz olarak kullanmak için argümanlar olarak öne sürdükleri bazı noktaları tartışmak istiyorum:

  1. Serileştirme:
    EricJ bir yorumda şunları söylüyor:

    Serileştirilebilen bir nesne, serileştirme yapıldığında yapıcısının çağrılmasını sağlamaz (serileştiriciye bağlıdır, ancak birçok yaygın olan bu şekilde davranır). Başlatma kodunu yapıcıya koymak, serileştirme için ek destek sağlamanız gerektiği anlamına gelir. Bu örüntü özel kodlamayı önler.

    Bu argümanla ilgili birkaç sorun var:

    1. Çoğu nesne asla serileştirilmez. Gerekmediğinde bir tür destek eklemek YAGNI'yı ihlal ediyor .
    2. Bir sınıfın serileştirmeyi desteklemesi gerektiğinde, ilk bakışta serileştirme ile ilgisi olmayan bir geçici çözüm olmadan etkinleştirmenin yolları vardır.
  2. Mikro optimizasyon: Temel argümanınız, nesneleri sadece birisi gerçekten eriştiğinde oluşturmak istediğinizdir. Yani aslında bellek kullanımını optimize etmekten bahsediyorsunuz.
    Aşağıdaki nedenlerden dolayı bu tartışmaya katılmıyorum:

    1. Çoğu durumda, bellekteki birkaç nesnenin hiçbir şey üzerinde hiçbir etkisi yoktur. Modern bilgisayarların yeterince hafızası vardır. Bir profil oluşturucu tarafından onaylanan gerçek sorunlar olmadan, bu önceden olgunlaşmış bir optimizasyondur ve buna karşı iyi nedenler vardır.
    2. Bazen bu tür bir optimizasyonun haklı olduğunu kabul ediyorum. Ancak bu durumlarda bile tembel başlatma doğru çözüm gibi görünmemektedir. Buna karşı konuşan iki neden var:

      1. Tembel başlatma potansiyel olarak performansı zedeler. Belki sadece marjinal olarak, ama Bill'in cevabının gösterdiği gibi, etki ilk bakışta düşünülenden daha büyük. Dolayısıyla bu yaklaşım temelde performansı belleğe göre değiştirir.
      2. Sınıfın yalnızca bazı bölümlerini kullanmanın yaygın olarak kullanıldığı bir tasarımınız varsa, bu tasarımın kendisiyle ilgili bir soruna işaret eder: Söz konusu sınıfın büyük olasılıkla birden fazla sorumluluğu vardır. Çözüm, sınıfı daha odaklı birkaç sınıfa ayırmak olacaktır.

4
@JohnWillemse: Bu, mimarinizin bir sorunu. Sınıflarınızı daha küçük ve daha odaklanmış olacak şekilde yeniden düzenlemelisiniz. 5 farklı şey / görev için bir sınıf oluşturmayın. Bunun yerine 5 sınıf oluşturun.
Daniel Hilgarth

26
@JohnWillemse Belki de bunu erken optimizasyon örneği olarak düşünün. Ölçülen bir performans / bellek darboğunuz olmadığı sürece , karmaşıklığı arttırdığı ve iplik geçirme sorunları getirdiği için buna karşı tavsiye ederim.
Chris Sinclair

2
+1, bu sınıfların% 95'i için iyi bir tasarım seçeneği değildir. Tembel başlatmanın artıları vardır, ancak TÜM mülkler için genelleştirilmemelidir. Durumların% 99'unda algılanabilir bir optimizasyon için karmaşıklık, kodu okuma zorluğu, iş parçacığı güvenliği sorunları ekler. Ayrıca, SolutionYogi'nin bir yorum olarak söylediği gibi, OP'nin kodu buggy'dir, bu da bu modelin uygulanması önemsizdir ve tembel başlatma gerçekten gerekli olmadıkça kaçınılmalıdır.
ken2k

2
@DanielHilgarth Bu kalıbı koşulsuz olarak kullanarak yanlış olan her şeyi (neredeyse) yazmak için her yere gittiğin için teşekkürler. İyi iş!
Alex

1
@DanielHilgarth Evet evet ve hayır. İhlal burada sorun yani evet. Ama aynı zamanda 'hayır' çünkü POLS kesinlikle koddan şaşıramayacağınız ilkesidir . Foo programınızın dışında kalmadıysa, alabileceğiniz ya da alamadığınız bir risktir. Bu durumda, sonuçlara şaşıracağınızı neredeyse garanti edebilirim , çünkü özelliklere erişme şeklini kontrol etmezsiniz. Risk bir hata nullhaline geldi ve dava hakkındaki argümanınız daha da güçlendi. :-)
atlaste

49

İyi bir tasarım seçimidir. Kütüphane kodu veya çekirdek sınıflar için şiddetle önerilir.

Bazı "tembel başlatma" veya "gecikmeli başlatma" olarak adlandırılır ve genellikle herkes tarafından iyi bir tasarım seçeneği olarak kabul edilir.

İlk olarak, sınıf düzeyi değişkenleri veya kurucu bildirimlerinde başlatırsanız, nesneniz oluşturulduğunda, asla kullanılmayacak bir kaynak oluşturma yükünüz olur.

İkinci olarak, kaynak yalnızca gerektiğinde oluşturulur.

Üçüncü olarak, kullanılmayan bir nesneyi çöp toplamaktan kaçının.

Son olarak, mülkte oluşabilecek başlatma istisnalarını, daha sonra sınıf seviyesi değişkenlerinin veya kurucuyu başlatma sırasında oluşan istisnaları işlemek daha kolaydır.

Bu kuralın istisnaları vardır.

"Get" özelliğindeki başlatma için ek denetimin performans bağımsız değişkeniyle ilgili olarak, önemsizdir. Bir nesneyi başlatmak ve atmak, bir sıçrama ile basit bir boş gösterici kontrolünden daha önemli bir performans vuruşudur.

Tasarım Kuralları sınıf kitaplıkları Geliştirme en http://msdn.microsoft.com/en-US/library/vstudio/ms229042.aspx

ilişkin Lazy<T>

Genel Lazy<T>sınıf tam olarak posterin istediği şey için yaratılmıştır, bkz . Http://msdn.microsoft.com/en-us/library/dd997286(v=vs.100).aspx adresindeki Tembel Başlatma . .NET'in daha eski sürümlerine sahipseniz, soruda gösterilen kod modelini kullanmanız gerekir. Bu kod deseni o kadar yaygın hale geldi ki Microsoft, kalıbın uygulanmasını kolaylaştırmak için en son .NET kitaplıklarına bir sınıf eklemek için uygun gördü. Ayrıca, uygulamanızın iş parçacığı güvenliğine ihtiyacı varsa, bunu eklemeniz gerekir.

İlkel Veri Türleri ve Basit Sınıflar

Obvioulsy, ilkel veri türü veya basit sınıf kullanımı için tembel başlatma kullanmazsınız List<string>.

Lazy hakkında yorum yapmadan önce

Lazy<T> .NET 4.0'da tanıtıldı, bu yüzden lütfen bu sınıfla ilgili başka bir yorum eklemeyin.

Mikro Optimizasyonlar Hakkında Yorum Yapmadan Önce

Kütüphaneler oluştururken, tüm optimizasyonları göz önünde bulundurmalısınız. Örneğin, .NET sınıflarında, yalnızca iki "mikro optimizasyon" olarak adlandırmak üzere bellek tüketimini ve bellek parçalanmasını azaltmak için kod boyunca Boole sınıf değişkenleri için kullanılan bit dizilerini göreceksiniz.

Kullanıcı Arayüzleri Hakkında

Doğrudan kullanıcı arabirimi tarafından kullanılan sınıflar için tembel başlatmayı kullanmayacaksınız. Geçen hafta, bir günün daha iyi bir kısmını birleşik giriş kutuları için bir görünüm modelinde kullanılan sekiz koleksiyonun tembel yüklemesini kaldırarak geçirdim. LookupManagerHerhangi bir kullanıcı arabirimi öğesi için gerekli koleksiyonları tembel yükleme ve önbelleğe alma işleyen bir var.

"Setters"

Hiç tembel yüklenen özelliği için bir set özelliği ("setters") kullanmadım. Bu nedenle, asla izin vermezdiniz foo.Bar = null;. Ayarlamanız gerekiyorsa, Baradında bir yöntem oluşturacağım SetBar(Bar value)ve tembel başlatma kullanmam

Koleksiyonları

Sınıf koleksiyonu özellikleri her zaman boş bırakılmaması gerektiğinden bildirildiğinde başlatılır.

Karmaşık Sınıflar

Bunu farklı şekilde tekrarlayayım, karmaşık sınıflar için tembel başlatma kullanıyorsunuz. Bunlar genellikle kötü tasarlanmış sınıflardır.

son olarak

Bunu asla tüm sınıflar için veya her durumda yapmayı söylemedim. Kötü bir alışkanlık.


6
Herhangi bir müdahale değeri ayarı yapmadan farklı iş parçacıklarında foo.Bar öğesini birden çok kez çağırabilir, ancak farklı değerler elde ederseniz, kötü bir zayıf sınıfınız olur.
Yalan Ryan

25
Bence bu pek çok düşüncesi olmayan kötü bir kural. Bar, bilinen bir kaynak domuzu olmadığı sürece, bu gereksiz bir mikro optimizasyondur. Ve Bar'ın kaynak yoğun olması durumunda, .net içine yerleştirilmiş Lazy <T> iş parçacığı vardır.
Andrew Hanlon

10
"özellikte oluşabilecek başlatma istisnalarını, sonra sınıf düzeyi değişkenlerinin veya kurucuyu başlatma sırasında oluşan istisnaları işlemek daha kolaydır." - tamam, bu aptalca. Bir nesne herhangi bir nedenle başlatılamazsa, en kısa sürede bilmek istiyorum. Yani inşa edildiğinde hemen. Tembel başlatmayı kullanmak için iyi argümanlar var, ancak bunu yaygın olarak kullanmanın iyi bir fikir olduğunu düşünmüyorum .
milimoose

20
Diğer geliştiricilerin bu yanıtı görmesinden ve bunun gerçekten iyi bir uygulama olduğunu düşünmesinden gerçekten endişeliyim (ah oğlum). Eğer koşulsuz olarak kullanıyorsanız bu çok kötü bir uygulamadır. Daha önce söylenenlerin yanı sıra, çok az kazanç (hiç kazanç varsa) için herkesin hayatını çok daha zorlaştırıyorsunuz (müşteri geliştiricileri ve bakım geliştiricileri için). Profesyonellerden dinlemelisiniz: Donald Knuth, Bilgisayar Programlama Sanatı serisinde, ünlü "erken optimizasyon tüm kötülüğün kökü" dedi. Yaptığınız şey sadece kötülük değil, şeytani!
Alex

4
Yanlış yanıtı (ve yanlış programlama kararını) seçtiğiniz çok fazla gösterge var. Listenizdeki profesyonellerden daha fazla eksileri var. Buna karşı kefil olan daha çok insan var. Bu sitede yayınlanan daha deneyimli siteler (@BillK ve @DanielHilgarth) buna karşı. İş arkadaşınız zaten bunun yanlış olduğunu söylemişti. Cidden, yanlış! Bunu yaparken ekibimin geliştiricilerinden birini (takım lideriyim) yakalarsam, 5 dakikalık bir zaman aşımı süresine neden olur ve bunu neden asla yapmaması gerektiğini anlar.
Alex

17

Bu tür bir kalıp kullanarak uygulamayı düşünüyor musunuz Lazy<T>?

Tembel yüklenen nesnelerin kolayca oluşturulmasına ek olarak, nesne başlatılırken iş parçacığı güvenliği elde edersiniz:

Diğerlerinin de söylediği gibi, nesneleri gerçekten kaynak açısından ağırsa tembel olarak yüklüyorsunuz veya nesne oluşturma sırasında bunları yüklemek zaman alıyor.


Teşekkürler, şimdi anlıyorum ve kesinlikle Lazy<T>şimdi bakacağım ve her zaman yaptığım şekilde kullanmaktan kaçınacağım.
John Willemse

1
Sihirli iş parçacığı güvenliği elde edemezsiniz ... hala düşünmek zorundasınız. MSDN'den:Making the Lazy<T> object thread safe does not protect the lazily initialized object. If multiple threads can access the lazily initialized object, you must make its properties and methods safe for multithreaded access.
Eric J.

@EricJ. Tabiki tabiki. Yalnızca nesneyi başlatırken iş parçacığı güvenliği elde edersiniz, ancak daha sonra başka bir nesne olarak senkronizasyonla uğraşmanız gerekir.
Matías Fidemraizer

9

Bence ne başlattığınıza bağlı. Muhtemelen bir liste için yapmazdım çünkü inşaat maliyeti oldukça küçüktür, bu yüzden yapıcıya gidebilir. Ama önceden doldurulmuş bir liste olsaydı, muhtemelen ilk kez gerekene kadar yapmazdım.

Temel olarak, inşaat maliyeti her erişim için bir koşullu kontrol yapma maliyetinden ağır basarsa tembel oluşturun. Değilse, yapıcıda yapın.


Teşekkür ederim! Mantıklı.
John Willemse

9

Görebildiğim dezavantajı, Bars null olup olmadığını sormak isterseniz, asla olmayacak ve listeyi orada yaratacağınızdır.


Bunun bir dezavantaj olduğunu düşünmüyorum.
Peter Porfy

Bu neden bir dezavantaj? Bunun yerine null yerine herhangi biriyle kontrol edin. if (! Foo.Bars.Any ())
s.meijer

6
@PeterPorfy: Bu ihlal Pöls . Sen koy null, ama geri alma. Normalde, bir mülke koyduğunuz değeri geri aldığınız varsayılır.
Daniel Hilgarth

@DanielHilgarth Tekrar teşekkürler. Bu daha önce düşünmediğim çok geçerli bir argüman.
John Willemse

6
@ AMissico: Bu uydurma bir kavram değil. Ön kapının yanındaki bir düğmeye basmanın bir kapı zilini çalması gibi, özelliklere benzeyen şeylerin de benzer özelliklere sahip olması beklenir. Özellikle düğme bu şekilde etiketlenmemişse, ayaklarınızın altında bir tuzak kapısı açmak şaşırtıcı bir davranıştır.
Bryan Boettcher

8

Tembel örnekleme / başlatma mükemmel şekilde uygulanabilir bir modeldir. Bununla birlikte, genel bir kural olarak API'nızın tüketicilerinin alıcıların ve ayarlayıcıların son kullanıcı POV'sinden (veya başarısız olmasını) fark edilebilir bir zaman almasını beklemediğini unutmayın.


1
Katılıyorum ve sorumu biraz düzenledim. Altta yatan bir yapıcı zincirinin, sadece gerekli olduğunda sınıfları başlatmaktan daha fazla zaman almasını bekliyorum.
John Willemse

8

Sadece Daniel'in cevabı hakkında bir yorum yazacaktım ama dürüstçe bunun yeterince ileri gittiğini düşünmüyorum.

Bu, belirli durumlarda (örneğin, nesne veritabanından başlatıldığında) kullanmak için çok iyi bir kalıp olmasına rağmen, içine girmek HORRIBLE bir alışkanlıktır.

Bir nesne hakkında en iyi şeylerden biri, güvenli ve güvenilir bir ortam sunmasıdır. En iyi durum, mümkün olduğunca çok sayıda "Final" alanı oluşturup hepsini yapıcı ile doldurmanızdır. Bu, sınıfınızı oldukça kurşun geçirmez hale getirir. Alanların ayarlayıcılarla değiştirilmesine izin vermek biraz daha az, ancak korkunç değil. Örneğin:

sınıf SafeClass
{
    Dize adı = "";
    Tam sayı yaşı = 0;

    public void setName (Dize newName)
    {
        assert (yeniAd! = boş)
        = NewName isim;
    } // yaş için bu modeli izleyin
    ...
    public String toString () {
        Dize s = "Güvenli Sınıfın adı:" + ad + "ve yaş:" + yaş
    }
}

Deseninizle toString yöntemi şöyle görünür:

    eğer (name == null)
        yeni IllegalStateException ("SafeClass geçersiz bir duruma geldi! name null")
    eğer (yaş == null)
        yeni IllegalStateException ("SafeClass geçersiz bir duruma geldi! yaş boş")

    public String toString () {
        Dize s = "Güvenli Sınıfın adı:" + ad + "ve yaş:" + yaş
    }

Sadece bu değil, aynı zamanda sınıfınızda bu nesneyi kullanabileceğiniz her yerde null kontrollere ihtiyacınız var (Sınıfınızın dışında, alıcıdaki boş kontrol nedeniyle güvenlidir, ancak çoğunlukla sınıf içindeki sınıf üyelerinizi kullanmalısınız)

Ayrıca sınıfınız sürekli olarak belirsiz bir durumdadır - örneğin, birkaç ek açıklama ekleyerek o sınıfı bir hazırda bekletme sınıfı yapmaya karar verdiyseniz, bunu nasıl yapardınız?

Gereksinimler ve testler olmadan bazı mikro-optomizasyona dayalı herhangi bir karar verirseniz, bu kesinlikle yanlış bir karardır. Aslında, durumunuzun en ideal koşullarda bile sistemi yavaşlatması gerçekten çok iyi bir şans var, çünkü if ifadesi CPU'da bir şeyleri çok daha fazla yavaşlatacak bir şube tahmin hatasına neden olabilir yalnızca oluşturduğunuz nesne oldukça karmaşık veya uzak bir veri kaynağından gelmedikçe yapıcıya bir değer atamak.

Brance tahmin problemine bir örnek (tekrar tekrar, sadece bir kez olmak üzere), bu harika sorunun ilk cevabına bakın: Sıralanmamış bir diziyi işlemek neden sıralanmamış bir diziden daha hızlı?


Girdiniz için teşekkürler. Benim durumumda, sınıfların hiçbirinde null olup olmadığını kontrol etmek için herhangi bir yöntem yoktur, bu yüzden bu bir sorun değildir. Diğer itirazlarınızı dikkate alacağım.
John Willemse

Bunu gerçekten anlamıyorum. Üyelerinizi depolandıkları sınıflarda kullanmadığınız anlamına gelir - sınıfları sadece veri yapıları olarak kullanırsınız. Bu durumda , nesne durumunu harici olarak değiştirerek kodunuzun nasıl geliştirilebileceğinin iyi bir açıklamasına sahip olan javaworld.com/javaworld/jw-01-2004/jw-0102-toolbox.html dosyasını okumak isteyebilirsiniz . Bunları dahili olarak manipüle ediyorsanız, her şeyi tekrar tekrar null kontrol etmeden nasıl yaparsınız?
Bill K

Bu cevabın bazı kısımları iyidir, fakat bazı kısımlar birbirinden farklı görünür. Bu modeli kullanırken Normalde toString()çağırır getName()kullanmayın, namedoğrudan.
Şubat'ta Izkata

@BillK Evet, sınıflar çok büyük bir veri yapısıdır. Tüm işler statik sınıflarda yapılır. Bağlantıdaki makaleyi kontrol edeceğim. Teşekkürler!
John Willemse

1
@izkata Aslında bir sınıfın içinde, bir alıcıyı kullandığınız veya kullanmamanız için hava durumu gibi bir atma gibi görünüyor, çalıştığım çoğu yer üyeyi doğrudan kullandı. Bu bir yana, her zaman bir alıcı kullanıyorsanız, dal tahmin hataları daha sık olacağı için if () yöntemi daha da zararlıdır VE dallanma nedeniyle çalışma zamanının alıcıyı içe aktarmada daha fazla sorunu olacaktır. Bununla birlikte, john'un vahiyleri ile veri yapıları ve statik sınıflar oldukları, bu en çok ilgilendiğim şey, tartışmalı.
Bill K

4

Başkaları tarafından yapılan birçok iyi noktaya bir puan daha ekleyeyim ...

Hata ayıklayıcı ( varsayılan olarak ), kodun üzerinden geçerken özellikleri, Baryalnızca kodu yürüterek normalden daha erken başlatabilecek şekilde değerlendirir . Başka bir deyişle, sadece hata ayıklama eylemi programın yürütülmesini değiştirmektedir.

Bu bir sorun olabilir veya olmayabilir (yan etkilere bağlı olarak), ancak bilinmesi gereken bir şeydir.


2

Foo'nun herhangi bir şeyi somutlaştırması gerektiğinden emin misiniz?

Bana göre, Foo'nun herhangi bir şey başlatmasına izin vermek (her zaman yanlış olmasa da ) kötü kokulu görünüyor . Foo'nun bir fabrika olmasının açık amacı olmadığı sürece, kendi ortak çalışanlarını somutlaştırmamalı, bunun yerine üreticisine enjekte etmelidir .

Ancak Foo'nun var olma amacı Bar tipi örnekler oluşturmaksa, tembel olarak yapmakta yanlış bir şey görmüyorum.


4
@BenjaminGruenbaum Hayır, pek değil. Saygılarımla, öyle olsa bile, hangi noktayı yapmaya çalışıyordunuz?
KaptajnKold
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.