Senin sorun.
Ama, ama - saflığımdan çığlık atmama izin ver - bazen bir değer anlamlı olamaz
Tamamen orada seninle gemide. Ancak, bir saniye içinde bulacağım bazı uyarılar var. Ama önce:
Boş değerler kötüdür ve mümkün olduğunda kaçınılmalıdır.
Bence bu iyi niyetli, ancak genelleşmiş bir ifadedir.
Boşlar kötü değildir. Antipattern değiller. Ne pahasına olursa olsun kaçınılması gereken bir şey değildir. Bununla birlikte, boş değerler hataya açıktır (boş değeri kontrol etmekte başarısız).
Ancak boş değeri kontrol etmemenin, boşalmanın kullanımının yanlış olduğunu bir şekilde kanıtladığını anlamıyorum.
Eğer boş ise, o zaman dizi dizinleri ve C ++ işaretçileri de öyle. Onlar değil. Kendini ayağından vurmaları kolay, ama ne pahasına olursa olsun kaçınılması gerekmiyor.
Bu cevabın geri kalanı için, "boş olan şeytan" ın niyetini daha nüanslı bir " boş olanın sorumlu bir şekilde ele alınması " na uyarlayacağım .
Senin çözüm.
Global kural olarak null kullanımı hakkındaki görüşünle aynı fikirdeyken; Bu durumda boş kullanmanızla aynı fikirde değilim.
Aşağıdaki geri bildirimleri özetlemek için: kalıtım ve polimorfizmin amacını yanlış anlıyorsunuz. Null kullanma argümanınız geçerliliğe sahipken, diğer yolun neden kötü olduğuna dair daha fazla "kanıtınız" mirasın yanlış kullanılması üzerine kuruludur, bu da puanlarınızı null problemiyle bir miktar alakasız hale getirir.
Çoğu güncelleme doğal olarak kendileriyle ilişkili bir Oynatıcıya sahiptir - sonuçta, bu sırayı hangi oyuncunun yaptığını bilmek gerekir. Ancak, bazı güncellemeler anlamlı bir şekilde onlarla ilişkilendirilmiş bir Player'a sahip olamaz.
Bu güncellemeler anlamlı bir şekilde farklıysa (hangileri), o zaman iki ayrı güncelleme türüne ihtiyacınız vardır.
Mesela mesajları düşünün. Hata mesajlarınız ve IM sohbet mesajlarınız var. Ancak çok benzer veriler (bir dize mesajı ve bir gönderen) içerebilse de, aynı şekilde davranmazlar. Farklı sınıflar olarak ayrı ayrı kullanılmaları gerekir.
Şu anda yaptığınız şey, Player özelliğinin boşluğuna bağlı olarak iki güncelleme türü arasında etkili bir şekilde ayrım yapmak. Bu bir IM mesajı ile bir hata kodunun varlığına dayanan bir hata mesajı arasında karar vermeye eşdeğerdir. Çalışıyor, ama en iyi yaklaşım değil.
- JS kodu şimdi Player'ın tanımlanmayan bir özelliği olarak basit bir nesneyi alacak, bu değer her iki durumda da değerin var olup olmadığını kontrol etmeyi gerektirdiğinden boş olduğu gibi aynı olacaktır;
Sizin argüman polimorfizm yanlışlarına dayanır. Bir döndüren bir yöntem varsa GameUpdate
nesne, genellikle hiç ayırt etmek bakım gerekir GameUpdate
, PlayerGameUpdate
ya da NewlyDevelopedGameUpdate
.
Bir temel sınıfın tam olarak çalışan bir sözleşmeye ihtiyacı vardır, yani özellikleri türetilmiş sınıfta değil, temel sınıfta tanımlanır (yani , bu temel özelliklerin değeri elbette türetilmiş sınıflarda geçersiz kılınabilir).
Bu argüman tartışmanızı sağlar. İyi uygulamalarda, GameUpdate
nesnenizin oyuncu olup olmamasına asla dikkat etmemelisiniz . A Player
özelliğine erişmeye çalışıyorsan GameUpdate
, mantıksız bir şey yapıyorsun.
C # gibi Yazılan diller bile olmaz izin denemek ve erişim için Player
bir malı GameUpdate
çünkü GameUpdate
basitçe özelliği yoktur. Javascript yaklaşımı bakımından oldukça kayıtsızdır (ve önceden derleme gerektirmez), bu yüzden sizi düzeltmek için zahmete girmez ve çalışma zamanında havaya uçurmasını sağlar.
- GameUpdate sınıfına başka bir null alanı eklenirse, bu tasarımı devam ettirmek için çoklu kalıtım kullanmak zorunda kalacağım - ama MI kendi başına kötülük (daha deneyimli programcılara göre) ve daha da önemlisi, C # yok Sahip olduğum için kullanamam.
Null özelliklerine ek olarak dayalı sınıflar oluşturmamalısınız. İşlevsel olarak benzersiz oyun güncellemeleri türlerine dayanan sınıflar oluşturmalısınız .
Genel olarak null ile ilgili sorunlardan nasıl kaçınılır?
Bir değerin yokluğunu nasıl anlamlı bir şekilde ifade edebileceğinizi açıklamakla alakalı olduğunu düşünüyorum. Bu, belirli bir düzende olmayan bir çözüm (veya kötü yaklaşım) topluluğudur.
1. Yine de null kullanın.
Bu en kolay yaklaşımdır. Bununla birlikte, bir sürü boş kontrol için kendinizi kaydettiriyorsunuz ve (bunu yapmazken) boş referans istisnalarını gideriyorsunuz.
2. Boş olmayan bir anlamsız değer kullanın
Burada basit bir örnek indexOf()
:
"abcde".indexOf("b"); // 1
"abcde".indexOf("f"); // -1
Bunun yerine null
, olsun -1
. Teknik düzeyde, bu geçerli bir tamsayı değeridir. Ancak, negatif bir değer saçma bir cevaptır çünkü indekslerin pozitif tamsayılar olması beklenir.
Mantıksal olarak, bu yalnızca dönüş türünün anlamlı şekilde döndürülenden daha olası değerlere izin verdiği durumlarda kullanılabilir (indexOf = pozitif tamsayılar; int = negatif ve pozitif tamsayılar)
Referans tipleri için hala bu prensibi uygulayabilirsiniz. Örneğin, bir tamsayı kimliğine sahip bir varlığınız varsa, kimliği boş olanın aksine kimliği -1 olan bir kukla nesne döndürebilirsiniz.
Bir nesnenin gerçekten kullanılabilir olup olmadığını ölçebileceğiniz bir “sahte durum” tanımlamanız gerekir.
Dize değerini kontrol etmiyorsanız önceden belirlenmiş dize değerlerine güvenmemeniz gerektiğini unutmayın. Boş bir nesne döndürmek istediğinizde bir kullanıcının adını "null" olarak ayarlamayı düşünebilirsiniz, ancak Christopher Null hizmetinize kaydolduğunda sorunlarla karşılaşırsınız .
3. Bunun yerine bir istisna atın.
Hayır sadece hayır. Mantıksal akış için istisnalar ele alınmamalıdır.
Olduğu söyleniyor, (nullreference) istisnasını gizlemek istemediğiniz ancak uygun bir istisna göstermek istediğiniz bazı durumlar var. Örneğin:
var existingPerson = personRepository.GetById(123);
Bu, PersonNotFoundException
ID 123 olan bir kişi olmadığında (veya benzerini) atabilir .
Biraz açık bir şekilde, bu yalnızca bir öğenin bulunmamasının başka bir işlem yapmayı imkansız hale getirdiği durumlar için kabul edilebilir. Bir öğeyi bulamazsanız ve uygulama devam edebilirse, ASLA bir istisna atmamalısınız . Bunu yeterince vurgulamıyorum.