'Statik' anahtar kelimeyi 'final' anahtar kelimesi olmadan kullanıyorsanız, bu tasarımınızı dikkatlice değerlendirmek için bir işaret olmalıdır. Değişken bir statik nihai nesne de aynı derecede tehlikeli olabileceğinden, bir 'final' varlığı bile serbest geçiş değildir.
Bir 'final' olmadan 'statik' gördüğüm zamanın yaklaşık% 85'ini tahmin ediyorum, YANLIŞ. Genellikle, bu sorunları maskelemek veya gizlemek için garip çözümler bulurum.
Lütfen statik değişkenler oluşturmayın. Özellikle Koleksiyonlar. Genel olarak Koleksiyonlar, içerdikleri nesne başlatıldığında başlatılmalı ve içerdikleri nesne unutulduğunda sıfırlanacak veya unutulacak şekilde tasarlanmalıdır.
Statik kullanmak, mühendislerin günlerce acı çekmesine neden olacak çok ince hatalar oluşturabilir. Biliyorum, çünkü bu böcekleri hem yarattım hem de avladım.
Daha fazla ayrıntı istiyorsanız, lütfen okumaya devam edin…
Neden Statik Kullanılmıyor?
Statik, test yazma ve yürütme ve hemen belli olmayan ince hatalar dahil olmak üzere birçok sorun var.
Statik nesnelere dayanan kod kolayca birim testinden geçirilemez ve statikler kolayca alay edilemez (genellikle).
Statik kullanırsanız, daha yüksek seviyedeki bileşenleri test etmek için sınıfın uygulanmasını değiştirmek mümkün değildir. Örneğin, veritabanından yüklediği Müşteri nesnelerini döndüren statik bir CustomerDAO düşünün. Şimdi, bazı Customer nesnelerine erişmesi gereken bir sınıf CustomerFilter var. CustomerDAO statik ise, önce veritabanımı başlatmadan ve faydalı bilgileri doldurmadan CustomerFilter için bir test yazamıyorum.
Ve veritabanı nüfusu ve başlatma uzun zaman alıyor. Deneyimlerime göre, DB başlatma çerçeveniz zamanla değişecek, yani veriler değişecek ve testler bozulabilir. IE, Müşteri 1'in bir VIP olduğunu hayal edin, ancak DB başlatma çerçevesi değişti ve şimdi Müşteri 1 artık VIP değil, ancak testiniz Müşteri 1'i yüklemek için kodlanmıştı…
Daha iyi bir yaklaşım, bir CustomerDAO'yu başlatmak ve inşa edildiğinde MüşteriFiltresine aktarmaktır. (Daha da iyi bir yaklaşım, Spring veya başka bir Inversion of Control çerçevesini kullanmak olacaktır.
Bunu yaptıktan sonra, CustomerFilterTest'inizdeki alternatif bir DAO'yu hızlı bir şekilde alay edebilir veya saplayabilirsiniz, böylece test üzerinde daha fazla kontrole sahip olursunuz.
Statik DAO olmadan, test daha hızlı (db başlatma yok) ve daha güvenilir olacaktır (çünkü db başlatma kodu değiştiğinde başarısız olmaz). Örneğin, bu durumda, test söz konusu olduğunda, Müşteri 1'in VIP olmasını ve daima VIP olmasını sağlamak.
Testleri Yürütme
Statikler, birim test paketlerini birlikte çalıştırırken gerçek bir soruna neden olur (örneğin, Sürekli Entegrasyon sunucunuzla). Bir testten diğerine açık kalan ağ soketi nesnelerinin statik bir haritasını düşünün. İlk test 8080 numaralı bağlantı noktasında bir Soket açabilir, ancak test yırtıldığında Haritayı temizlemeyi unuttunuz. Şimdi ikinci bir test başlatıldığında, bağlantı noktası hala meşgul olduğundan 8080 bağlantı noktası için yeni bir Soket oluşturmaya çalıştığında çökmesi muhtemeldir. Ayrıca statik Koleksiyonunuzdaki Soket referanslarının kaldırılmadığını ve (WeakHashMap hariç) hiçbir zaman çöp toplanmaya uygun olmadığını ve bellek sızıntısına neden olmadığını hayal edin.
Bu aşırı genelleştirilmiş bir örnektir, ancak büyük sistemlerde bu sorun TÜM ZAMANINDA ortaya çıkar. İnsanlar, aynı JVM'de yazılımlarını tekrar tekrar başlatan ve durduran birim testlerini düşünmezler, ancak yazılım tasarımınızın iyi bir testidir ve yüksek kullanılabilirliğe yönelik istekleriniz varsa, bilmeniz gereken bir şeydir.
Bu sorunlar genellikle, örneğin DB erişiminiz, önbelleğe alma, mesajlaşma ve günlük katmanlarınız gibi çerçeve nesneleriyle ortaya çıkar. Java EE veya en iyi cins çerçeveler kullanıyorsanız, muhtemelen sizin için bunların çoğunu yönetirler, ancak benim gibi eski bir sistemle uğraşıyorsanız, bu katmanlara erişmek için birçok özel çerçeveniz olabilir.
Bu çerçeve bileşenlerine uygulanan sistem yapılandırması birim sınamaları arasında değişirse ve birim sınama çerçevesi bileşenleri yırtıp yeniden oluşturmazsa, bu değişiklikler etkili olmaz ve bir sınama bu değişikliklere dayandığında başarısız olur .
Çerçeve dışı bileşenler bile bu soruna tabidir. OpenOrders adlı statik bir harita düşünün. Birkaç açık sipariş oluşturan bir test yazıyorsunuz ve hepsinin doğru durumda olup olmadığını kontrol ediyorsunuz, sonra test sona eriyor. Başka bir geliştirici, ihtiyaç duyduğu siparişleri OpenOrders haritasına yerleştiren ikinci bir test yazıyor, ardından sipariş sayısının doğru olduğunu iddia ediyor. Tek tek çalışın, bu testlerin her ikisi de geçer, ancak bir pakette birlikte çalıştırıldığında başarısız olurlar.
Daha da kötüsü, başarısızlık testlerin yapıldığı sıraya bağlı olabilir.
Bu durumda, statikten kaçınarak daha iyi test güvenilirliği sağlamak için test örnekleri arasında veriyi sürdürme riskinden kaçınırsınız.
Hafif Böcekler
Yüksek kullanılabilirlikli bir ortamda çalışıyorsanız veya iş parçacıklarının başlatılabileceği ve durdurulabileceği herhangi bir yerde çalışıyorsanız, yukarıda kod test paketlerinde belirtilen endişe kodunuz üretim sırasında da geçerli olabilir.
Verileri saklamak için statik bir nesne kullanmak yerine, iş parçacıklarıyla uğraşırken, iş parçacığının başlangıç aşamasında başlatılan bir nesneyi kullanmak daha iyidir. Bu şekilde, iş parçacığı her başlatıldığında, nesnenin yeni bir örneği (potansiyel olarak yeni bir yapılandırmayla) oluşturulur ve iş parçacığının bir örneğinden sonraki örneğe kadar olan verilerden kaçınırsınız.
Bir iş parçacığı öldüğünde, statik bir nesne sıfırlanmaz veya çöp toplanmaz. “EmailCustomers” adında bir iş parçacığına sahip olduğunuzu ve başladığında statik bir String koleksiyonunu bir e-posta adresleri listesiyle doldurduğunu, ardından her bir adresi e-postayla göndermeye başladığını düşünün. İş parçacığının bir şekilde kesildiğini veya iptal edildiğini varsayalım, bu nedenle yüksek kullanılabilirlik çerçeveniz iş parçacığını yeniden başlatır. Sonra iş parçacığı başladığında, müşteri listesini yeniden yükler. Ancak koleksiyon statik olduğundan, önceki koleksiyondaki e-posta adresleri listesini tutabilir. Artık bazı müşteriler yinelenen e-postalar alabilir.
Bir Kenara: Statik Final
Teknik uygulama farklılıkları olmasına rağmen, “statik final” kullanımı etkili bir şekilde C # tanımının Java eşdeğeridir. AC / C ++ #define, derlemeden önce ön işlemci tarafından koddan çıkarılır. Bir Java "statik finali" yığının üzerinde bulunan bellekle sonuçlanır. Bu şekilde, C ++ 'daki bir "statik const" değişkenine bir #define kıyasla daha benzerdir.
özet
Umarım bu, statikin sorunlu olmasının birkaç temel nedenini açıklamaya yardımcı olur. Java EE veya Spring gibi modern bir Java çerçevesi kullanıyorsanız, bu durumların çoğuyla karşılaşmayabilirsiniz, ancak büyük bir eski kod gövdesiyle çalışıyorsanız, bunlar daha sık olabilir.