Boş değerlerin kötülük olması durumunda, bir değer anlamlı bir şekilde bulunamadığında ne kullanılmalıdır?


26

Bu, tekrar tekrar tekrarlanan ve beni şaşırtan kurallardan biridir.

Boş değerler kötüdür ve mümkün olduğunda kaçınılmalıdır .

Ama, ama - saflığımdan çığlık atmama izin ver - bazen bir değer anlamlı olamaz

Lütfen bunu şu an üzerinde çalıştığım bu patern karşıtı baskın korkunç koddan çıkan bir örnekle sormama izin verin . Bu, özünde, her iki oyuncunun sırasının aynı anda çalıştırıldığı, çok oyunculu bir web turn tabanlı oyundur (Pokemon'da olduğu gibi, satrançta olduğu gibi).

Her dönüşten sonra sunucu, istemci tarafındaki JS kodu için bir güncelleme listesi yayınlar. Güncelleme sınıfı:

public class GameUpdate
{
    public Player player;
    // other stuff
}

Bu sınıf JSON'a serileştirildi ve bağlı oyunculara gönderildi.

Ç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. Örnek: Oyun zorla bağlandı, çünkü eylemsiz dönüş sınırı aşıldı. Bu tür güncellemeler için bence oynatıcının boş bırakılması anlamlıdır.

Elbette, mirası kullanarak bu kodu "düzeltebilirim":

public class GameUpdate
{
    // stuff
}

public class GamePlayerUpdate : GameUpdate
{
    public Player player;
    // other stuff
}

Ancak bunun iki nedenden dolayı nasıl bir gelişme gösterdiğini göremiyorum:

  • 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;
  • 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.

Bu kodun bu parçasının, deneyimli, iyi bir programcının korku içinde çığlık atacağı çok sayıdan biri olduğuna dair bir ipucum var. Aynı zamanda, bu yerde bunun nasıl bir şeylere zarar verdiğini ve bunun yerine ne yapılması gerektiğini göremiyorum.

Bu konuyu bana açıklar mısınız?


2
Bu soru JavaScript'e özel mi? Birçok dilde bu amaç için bir İsteğe Bağlı tür vardır, ancak js'nin bir tane (bir tane yapabilseniz de) veya json ile çalışıp çalışmadığını bilmiyorum (Her ne kadar kötü boş denetimlerin bir parçası olsa da kodunuzun tamamı için
Richard Tingle

9
Bu kural sadece yanlıştır. Birisinin bu görüşe abone olacağından biraz şaşırdım. Bazı durumlarda null için bazı iyi alternatifler vardır. null, eksik bir değeri temsil etmek için gerçekten iyidir. Bunun gibi rasgele internet kurallarının kendi gerekçeli kararınıza güvenmenizi engellemesine izin vermeyin.
usr

1
@ usr - Tamamen katılıyorum. Null senin arkadaşın. IMHO, eksik bir değeri temsil etmenin daha net bir yolu yok. Hata bulmada size yardımcı olabilir, hata koşullarını çözmenize yardımcı olabilir, affetmeniz için yalvarmanıza yardımcı olabilir (dene / yakala). Ne sevmiyorum?
Scuba Steve

4
tasarım yazılımı ilk kurallarından biri "Her zaman boş kontrol edin" dir. Neden bu bile bir sorun akıl almaz akıl bana.
MattE,

1
@MattE - Kesinlikle. Neden gerçekten bir tasarım deseni tasarlayayım ki, Null temel araç kutunuzda olması iyi bir şey. Graham'ın önerdiği gibi, IMHO, beni aşırı mühendislik olarak vuruyor.
Scuba Steve

Yanıtlar:


20

Bir çok şey sıfırdan daha iyidir.

  • Boş bir dize ("")
  • Boş bir koleksiyon
  • "İsteğe bağlı" veya "belki" bir monad
  • Sessizce hiçbir şey yapmayan bir işlev
  • Sessizce hiçbir şey yapmayan yöntemlerle dolu bir nesne
  • Sorunun yanlış öncülünü reddeden anlamlı bir değer
    (bu, sizi en başta boş olarak değerlendiren şeydir)

İşin püf noktası bunun ne zaman yapılacağının farkına varmaktır. Null, yüzünüze havaya uçmakta gerçekten iyidir, ancak sadece onu kontrol etmeden noktadan çıkardığınızda. Nedenini açıklamak iyi değil.

Havaya uçurmanız gerekmediğinde ve boşluğu kontrol etmek istemiyorsanız, bu alternatiflerden birini kullanın. Yalnızca 0 veya 1 öğeye sahipse bir koleksiyona dönmek garip gelebilir, ancak eksik değerlerle sessizce başa çıkmanıza izin vermek gerçekten iyidir.

Monad'lar kulağa hoş geliyor ama burada yaptıkları tek şey, koleksiyon için geçerli boyutların 0 ve 1 olduğunu açıklamanıza izin vermesi.

Bunlardan herhangi biri, niyetini sıfırdan daha açık yapmak için daha iyi bir iş çıkarıyor. Bu en önemli fark.

Bir istisna atmak yerine neden geri döndüğünüzü anlamanıza yardımcı olabilir. İstisnalar, temel olarak bir varsayımı reddetmenin bir yoludur (tek yol değildir). İki çizginin kesiştiği noktayı istediğinizde, kesiştiklerini varsayıyorsunuzdur. Paralel olabilirler. Bir "paralel çizgiler" istisnası mı atmalısınız? Öyleyse yapabilirsin, ama şimdi bu istisnayı başka bir yerde halletmek veya sistemi durdurmasına izin vermek zorundasın.

Bulunduğunuz yerde kalmayı tercih ederseniz, bu varsayımın reddini, sonuçları veya reddeleri ifade edebilecek bir değere çevirebilirsiniz. O kadar garip değil. Her zaman cebir yapıyoruz . İşin püf noktası bu değeri anlamlı kılmaktır, böylece ne olduğunu anlayabiliriz.

Dönen değer sonuçları ve redleri ifade edebiliyorsa, her ikisini de işleyebilecek koda gönderilmesi gerekir. Polimorfizm burada kullanımı gerçekten güçlüdür. Çekler için null çekleri takas etmek yerine isPresent(), her iki durumda da iyi davranan kodu yazabilirsiniz. Ya boş değerleri varsayılan değerlerle değiştirerek ya da sessizce hiçbir şey yapmadan.

Boştaki sorun çok fazla şey ifade edebilmesidir. Böylece sadece bilgi yok ediyor.


En sevdiğim boş düşünce deneyimde , renkli bir ışık kullanarak şifreli mesajları bir konveyör banttan alarak, onları bir prize vidalayarak ve çalıştırarak kodlayan mesajları gösteren karmaşık bir Rube Goldbergian makinesi hayal etmenizi rica ediyorum . Sinyal, konveyör bandına yerleştirilen ampullerin farklı renkleri tarafından kontrol edilir.

Bu çok pahalı şeyi, mesajlar arasında bir işaretleyici olması gerektiğini belirten RFC3.14159 ile uyumlu hale getirmeniz istendi. İşaretçi hiç ışık içermemelidir. Tam olarak bir nabız sürmeli. Tek renkli bir ışığın normalde parladığı aynı zaman miktarı.

Sadece mesajların arasında boşluk bırakamazsınız, çünkü uygulama alarmları durdurur ve sokete sokulacak bir ampul bulamazsa durur.

Bu projeye aşina olan herkes, makineye veya kontrol koduna dokunduğunda titremektedir. Değiştirmesi kolay değil. Ne yaparsın? Dalış yapabilir ve bir şeyler kırmaya başlayabilirsiniz. Belki bu korkunç tasarım güncellemeleri. Evet, daha iyisini yapabilirsin. Ya da hademe ile konuşup yanan ampulleri toplamaya başlayabilirsiniz.

Bu polimorfik çözüm. Sistemin bir şeylerin değiştiğini bilmesi bile gerekmez.


Bunu çıkarabilirsen gerçekten çok hoş. Bir varsayımın anlamlı bir şekilde reddedilmesini bir değere kodlayarak, soruyu değişmeye zorlamanız gerekmez.

Sana 1 elma verirsem bana kaç tane elma borçlusun? -1. Çünkü sana dünden 2 elma borcum vardı. Burada “bana borçlusun” sorusunun varsayımı olumsuz bir rakamla reddedildi. Soru yanlış olmasına rağmen, bu cevapta anlamlı bilgi kodlanmıştır. Bunu anlamlı bir şekilde reddederek, soru değişmek zorunda kalmaz.

Ancak, bazen soruyu değiştirmek aslında gitmenin yoludur. Varsayım daha güvenilir hale getirilebilirse, yine de faydalı olsa da, bunu yapmayı düşünün.

Sorununuz normalde güncellemelerin oynatıcılardan gelmesidir. Ancak, 1. oyuncudan veya 2. oyuncudan gelmeyen bir güncellemeye ihtiyaç duyduğunuzu fark ettiniz. Her iki oyuncu da bunu söylemiyor, ne yapmalısınız? Oyuncu null bırakmak çok cazip görünüyor. Ancak bilgiyi yok eder. Bir kara delikte bilgiyi kodlamaya çalışıyorsun.

Oyuncu alanı size kimin taşındığını söylemez. Öyle sanıyorsun ama bu problem bunun bir yalan olduğunu kanıtlıyor. Oynatıcı alanı, güncellemenin nereden geldiğini size bildirir. Zaman aşımına uğrayan güncellemeniz oyun saatinden geliyor. Benim tavsiyem, saate hak ettiği krediyi vermek ve playeralanın ismini değiştirmek gibi bir şey source.

Bu şekilde eğer sunucu kapanıyorsa ve oyunu askıya almak zorunda kalırsa, neler olduğunu rapor eden ve kendisini güncellemenin kaynağı olarak listeleyen bir güncelleme gönderebilir.

Bu hiçbir zaman sadece bir şeyi dışarıda bırakmaman gerektiği anlamına mı geliyor? Hayır. Ancak , gerçekten iyi bilinen tek bir varsayılan varsayılan değer anlamına gelebilecek hiçbir şeyin ne kadar iyi kabul edilebileceğini düşünmeniz gerekir . Hiçbir şeyin aşırı kullanımı kolaydır. Kullanırken dikkatli ol. Hiçbir şeyin lehine olan bir düşünce okulu var . Konfigürasyon kongre olarak adlandırılır .

Kendim hoşuma gidiyor, ancak yalnızca bir sözleşme açıkça belirtildiği zaman. Yenilikleri bozmanın bir yolu olmamalıdır. Ama onu kullanıyor olsan bile, null hala yapmanın en iyi yolu değil. Boş, tehlikeli bir şey değil . Boş, kullanana kadar kullanabileceğin bir şeymiş gibi davranır, sonra evrende bir delik açar (anlamsal modelini bozar). Evrendeki bir deliği açmadıkça, neden bununla uğraşıyorsun? Başka bir şey kullan.


9
"yalnızca 0 veya 1 öğeye sahipse bir koleksiyon döndür" - Üzgünüm ama anlamadığımı sanmıyorum :( POV'umdan bunu yapmak (a) sınıfa gereksiz geçersiz durumlar ekleyerek (b) 'nin belgelendirilmesini gerektiriyor Koleksiyonda en fazla 1 eleman bulunmalıdır (c) sorunu yine de çözmedi gibi görünüyor, çünkü toplama, herhangi bir şekilde gerekli olmadan önce tek elemanını içeriyorsa, kontrol edilmesi gerekiyor, yoksa başka bir istisna atılacak mı?
gaazkam

2
@gaazkam görmek? Sana insanları rahatsız ettiğini söylemiştim. Yine de, boş dizeyi her kullandığınızda tam olarak yaptığınız şey.
candied_orange

16
Boş bir dize veya ayarlanmış olan geçerli bir değer olduğunda ne olur?
Blrfl

5
Her neyse @gaazkam, koleksiyonun eşyaları olup olmadığını görmek için açıkça kontrol etmiyorsun. Boş bir liste üzerinde döngü (veya haritalama) etkisi olmayan güvenli bir işlemdir.
RubberDuck,

3
Boş dönmek yerine birilerinin ne yapması gerektiği hakkındaki soruyu yanıtladığınızı biliyorum ama bu noktaların çoğuna katılmıyorum. Ancak dile özgü olmadığımız ve reddetmeyi reddettiğim her kuralı ihlal etmek için bir neden olduğu için
Liath

15

nullBurada gerçekten sorun değil. Sorun şu anki programlama dillerinin çoğunun eksik bilgilerle nasıl başa çıktığı; bu sorunu ciddiye almazlar (veya en azından tuzaklardan kaçınmak için ihtiyaç duydukları desteği ve güvenliği sağlamazlar). Bu, korkmayı öğrendiğimiz tüm sorunlara yol açar (Javas NullPointerException, Segfaults, ...).

Bu konuyla daha iyi nasıl baş edeceğimizi görelim.

Diğerleri Boş Nesne Desenini önerdi . Bazen uygulanabilir olduğunu düşündüğüm halde, yalnızca tek bedene uyan hiçbir varsayılan değer bulunmadığı birçok senaryo var. Bu gibi durumlarda, bulunmayan bilgilerin tüketicileri, eğer bu bilgiler eksikse, ne yapmaları gerektiğine kendileri için karar verebilmelidir.

Derleme zamanında boş işaretçilere karşı güvenlik sağlayan programlama dilleri (geçersiz güvenlik adı verilen) vardır. Bazı modern örnekler vermek için: Kotlin, Rust, Swift. Bu dillerde, eksik bilgi sorunu ciddiye alınmıştır ve null kullanıldığında tamamen ağrısızdır - derleyici sizi null değerlerini geçersiz kılmaktan alıkoyacaktır.
Java'da, @ Nullable / @ NotNull ek açıklamalarıyla birlikte derleyici + IDE eklentileri ile aynı etkiye ulaşmak için çaba sarf edilmiştir. Gerçekten başarılı değildi, ancak bu cevabın kapsamı dışında.

Muhtemel yokluğu ifade eden açık ve genel bir tür, bununla baş etmenin başka bir yoludur. Örneğin Java'da var java.util.Optional. İşe yarayabilir:
Bir proje ya da şirket düzeyinde, kurallar / kurallar belirleyebilirsiniz.

  • sadece yüksek kalitede 3. parti kütüphaneleri kullanın
  • Her zaman kullanmak java.util.Optionalyerinenull

Dil topluluğunuz / ekosisteminiz bu sorunu derleyici / tercümandan daha iyi ele almanın başka yollarını bulmuş olabilir.


Nazikçe detaylandırır mısınız, Java Seçeneklileri null değerlerinden daha iyi? Belgeleri okuduğumda, isteğe bağlı bir değer almaya çalışmak, değer yoksa; Öyle görünüyor ki aynı yerdeyiz: bir çek gerekli ve birini unutursak, battık mı?
gaazkam

3
@gaazkam Haklısın, derleme zamanı güvenliği sağlamaz. Ayrıca, İsteğe Bağlı'nın kendisi boş olabilir, başka bir konu. Ancak açıktır (değişkenlerin, muhtemelen sadece boş / doc yorum olmasıyla karşılaştırılmıştır). Bu, kod kodunun tamamı için bir kodlama kuralı oluşturulduğunda yalnızca gerçek bir fayda sağlar. Bir şeyleri boş bırakmayabilirsin. Bilgi yoksa, İsteğe Bağlı seçeneğini kullanın. Bu açıklığı zorlar. Her zamanki boş kontroller daha sonra Optional.isPresent
çağrılır

8
@ marstato, boş denetimlerin yerini almak isPresent() , Optional'ın önerilen kullanımı değildir
candied_orange

10

İfadede null'un kötü olduğuna dair bir değer göremiyorum. Bu konudaki tartışmaları kontrol ettim ve onlar sadece beni sabırsız ve rahatsız ediyor.

Null, bir şey ifade ettiği zaman, yanlış bir "sihirli değer" olarak kullanılabilir. Fakat oraya ulaşmak için oldukça bükülmüş bir programlama yapmanız gerekecekti.

Null "orada değil" anlamına gelmeli, bu henüz yaratılmadı (henüz) veya (zaten) argüman olması durumunda sağlanmadı veya sağlanmadı. Bu bir devlet değil, her şey eksik. Her zaman her durumdan farklı, geçerli ve anlamlı bir durum olan şeylerin yaratıldığı ve yok edildiği bir OO ortamında.

Null ile çalışma zamanı sırasında derleme sırasında bir tür güvenli güvenlik alternatifi ile şapırtılıldınız.

Tamamen doğru değil, değişkeni kullanmadan önce boş değeri kontrol etmediğim için bir uyarı alabilirim. Ve aynı değil. Amacı olmayan bir nesnenin kaynaklarını korumak istemeyebilirim. Daha da önemlisi, istenen davranışı elde etmek için alternatifi aynı şekilde kontrol etmek zorunda kalacağım. Bunu unutursam, çalışma zamanında tanımsız / istenmeyen bir davranış yerine NullReferenceException elde etmeyi tercih ederim.

Dikkat edilmesi gereken bir konu var. Çok iş parçacıklı bir bağlamda, boşluğu kontrol etmeden önce yerel bir değişkene atayarak yarış koşullarına karşı korunmanız gerekir.

Boştaki sorun, çok şey ifade edebileceğidir. Böylece sadece bilgi yok ediyor.

Hayır, hiçbir anlamı yoktur / etmemelidir, bu nedenle yok edilecek bir şey yoktur. Değişkenin / argümanın adı ve türü her zaman neyin eksik olduğunu söyler, bilmesi gereken tek şey budur.

Düzenle:

Yolun yarısını duyuyorum Video işlevsel programlama hakkında onun diğer yanıtlar birinde bağlantılı candied_orange ve çok ilginç. Bunun yararını belirli senaryolarda görebiliyorum. Şimdiye kadar gördüğüm fonksiyonel yaklaşım, etrafta dolaşan kod parçalarıyla birlikte, genellikle bir OO ayarında kullanıldığında beni sıkıyor. Ama sanırım onun yeri var. Bir yerde. Ve sanırım C # ile karşılaştığımda kafa karıştırıcı bir karmaşa olarak algıladığım şeyleri iyi bir iş yapan diller olacak, bunun yerine temiz ve uygulanabilir bir model sağlayan diller olacağını tahmin ediyorum.

Eğer bu işlevsel model sizin zihin setiniz / çerçeveniz ise, belgelenmiş hata tanımları gibi yanlış bir şekilde ileriye itmek için alternatif yoktur ve nihayetinde arayanın başından sonuna kadar sürüklenen biriken çöplerle ilgilenmesine izin verin. Görünüşe göre bu, işlevsel programlamanın nasıl çalıştığıdır. Sınırlama olarak adlandır, yeni bir paradigma deyin. Kutsal yollarda biraz daha devam etmelerini sağlayan fonksiyonel öğrenciler için bir saldırı olduğunu düşünebilirsiniz, heyecan verici yeni olasılıkları ortaya çıkaran bu yeni programlama yolundan memnun olabilirsiniz. Her neyse, bu dünyaya adım atmamın, geleneksel OO işlerini yapma biçimine (evet, istisnalar atabiliriz, özür dileriz), ondan bir konsept seçmemize anlamsız geliyor.

Herhangi bir kavram yanlış şekilde kullanılabilir. Durduğum yerden, sunulan "çözümler" boş bir kullanım için alternatif değil. Onlar başka bir dünyadan gelen kavramlardır.


9
Boş, neyi temsil ettiği hiçbir şeyin bilgisini yok etmez. Sessizce göz ardı edilmesi gereken hiçbir şey yok. Geçersiz bir durumdan kaçınmak için sistemi durdurması gereken hiçbir şey. Programcının berbat olduğu ve kodu düzeltmesi gereken hiçbir şey yok. Kullanıcının, var olmayan ve kibarca söylenmesi gereken bir şey istediği anlamına gelen hiçbir şey. Üzgünüm hayır. Bunların hepsi boş olarak kodlanmıştır. Bu nedenle, bunlardan herhangi birini null olarak kodlarsanız, hiç kimse ne demek istediğinizi bilmiyorsa şaşırmamalısınız. Bağlamdan tahmin etmeye bizi zorluyorsun.
candied_orange

3
@candied_orange İsteğe bağlı herhangi bir tür için aynı argümanı yapabilirsiniz: NoneTemsil….
Deduplicator

3
@candied_orange Hala ne demek istediğini anlamadım. Hiçbir şey yok mu? Eğer null kullanıyorsanız, belki de bir enum kullanmalıydınız? Sadece bir çeşit hiçbir şey yok. Bir şeyin bir şey olmama nedeni değişebilir, fakat bu hiçbir şeyi değiştirmez ya da bir şey olmamak için uygun cevabı değiştirmez. Orada olmayan ve kayda değer olan bir mağazada bir değer beklerseniz, sorgulayıp hiçbir şey almadığınız anda fırlatır veya oturum açarsanız, bir yönteme argüman olarak boş geçemezsiniz ve sonra bu yöntemde anlamaya çalışın neden boş verdin. Boş hata olmazdı.
Martin Maat

2
Boş, hata çünkü hiçbir şeyin anlamını kodlama şansın oldu. Hiçbir şeyi anlamanız hiçbir şeyin derhal ele alınmasını gerektirmez. 0, null, NaN, boş dize, boş küme, geçersiz, boş nesne, uygulanamaz, istisna uygulanmadı, hiçbir şey pek çok formda gelmiyor. Şu anda bildiklerini unutmak zorunda değilsin çünkü şu anda bildiklerinle uğraşmak istemiyorsun. Sizden -1'in karekökünü almanızı istersem, bunun imkansız olduğunu bildirmek ve her şeyi unutmak ya da hayali sayıları icat etmek ve bildiklerinizi korumak için bir istisna atabilirsiniz.
candied_orange 8:18

1
@MartinMaat, bir fonksiyon gibi görünmesini sağladığınızda beklentileriniz her ihlal edildiğinde bir istisna atmalıdır. Bu sadece doğru değil. Başa çıkmak için sık sık köşe durumlarda vardır. Gerçekten göremiyorsanız okumak bu
candied_orange

7

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 GameUpdatenesne, genellikle hiç ayırt etmek bakım gerekir GameUpdate, PlayerGameUpdateya 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, GameUpdatenesnenizin 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 Playerbir malı GameUpdateçünkü GameUpdatebasitç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, PersonNotFoundExceptionID 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.


5

Boş değerlerin kötü olmasının nedeni, eksik değerin boş olarak kodlanması değil, herhangi bir referans değerinin boş olabileceğidir. C # varsa, muhtemelen yine de kaybedilirsiniz. Bir referans tipi zaten isteğe bağlı olduğundan, burada bazı İsteğe Bağlı kullanım roları göremiyorum. Ancak Java için paket düzeyinde ayarlayabileceğiniz @Notnull ek açıklamaları var , sonra kaçırılabilecek değerler için @Nullable ek açıklamasını kullanabilirsiniz.


Evet! Sorun saçma bir varsayılandır.
Deduplicator

Katılmıyorum. Boş değerden kaçınan bir stilde programlama, daha az referans değişkeninin boş olmasına neden olur, boş olması gerekmeyen daha az referans değişkenine yol açar. % 100 değil, belki% 90'dır, ki buna değer IMO.
Monica

1

Boşlar kötü değildir, alternatif olarak herhangi bir alternatifi, boş gibi görünen bir şeyle uğraşmadan gerçekleştirmenin hiçbir yolu yoktur.

Boş değerler ancak tehlikelidir . Tıpkı diğer alçak seviye inşaatlarda olduğu gibi yanlış yaparsan seni yakalayacak hiçbir şey kalmaz.

Boş değerlere karşı birçok geçerli argüman olduğunu düşünüyorum:

  • Zaten yüksek seviyede bir etki alanındaysanız, düşük seviye modeli kullanmaktan daha güvenli desenler vardır.

  • Düşük seviyeli bir sistemin avantajlarına ihtiyacınız yoksa ve dikkatli olmaya hazır olmadıkça, belki düşük seviyeli bir dil kullanmamalısınız.

  • vb ...

Bunların hepsi geçerlidir ve ayrıca alıcılar ve ayarlayıcılar vb. Yazma çabasıyla uğraşmamak, bu tavsiyeye uymamak için ortak bir neden olarak görülmektedir. Çok sayıda programcının boş değerlerin tehlikeli ve tembel olduğu (kötü bir kombinasyon!) Olduğu sonucuna varılması şaşırtıcı değildir, ancak “evrensel” tavsiyelerin diğer birçok parçası gibi ifade ettikleri kadar evrensel değildir.

Dili yazan iyi insanlar, birileri için faydalı olacağını düşünüyordu. İtirazları anlıyor ve yine de sizin için doğru olduğunu düşünüyorsanız, başka hiç kimse daha iyisini bilemez.


Mesele şu ki, “evrensel tavsiye” genellikle insanların iddia ettiği gibi “evrensel” olarak ifade edilmez. Böyle bir tavsiyenin orijinal kaynağını bulursanız, genellikle deneyimli programcıların bildiği uyarılardan söz ederler. Olan, başka birisinin tavsiyesini okuduğu zaman, bu uyarıları görmezden gelme ve sadece “evrensel tavsiye” kısmını hatırlama eğiliminde olmalarıdır, bu yüzden bu tavsiyeyi başkalarıyla ilişkilendirdiğinde, ortaya çıkanı amaçlayandan çok daha “evrensel” olarak ortaya çıkar. .
Nicol Bolas

1
@NicolBolas, haklısın, ancak asıl kaynak çoğu kişinin alıntı yaptığı tavsiye değil, iletilen mesaj. Yapmak istediğim nokta, sadece pek çok programcının “Asla X yapmayın, X kötü / kötü / ne olursa olsun” olarak söylenmesiydi ve tam olarak söylediğiniz gibi, çok fazla uyarı gelmiyordu. Belki düşürülmüşlerdir, belki de hiç bulunmamışlardır, sonuç aynıdır.
drjpizzle

0

Java, herhangi bir değere güvenle erişebilmek Optionaliçin açık ifPresent+ lambda içeren bir sınıfa sahiptir . Bu JS'de de yapılabilir:

Bu StackOverflow sorusuna bakın .

Bu arada: Pek çok kişi, bu kullanımı şüpheli bulacak, ancak sanmıyorum. İsteğe bağlı özellikler var.


Bir de referans java.lang.Optionalolamaz nullmı?
Deduplicator

@Deduplicator Hayır, Optional.of(null)bir istisna atar, Optional.ofNullable(null)verirdi Optional.empty()- orada olmayan değeri.
Joop Eggen

Ve Optional<Type> a = null?
Deduplicator

@Deduplicator true, ancak orada kullanmalısınız Optional<Optional<Type>> a = Optional.empty();;) - JS'de (ve diğer dillerde) başka bir deyişle, bu gibi şeyler mümkün olmayacaktır. Scala varsayılan değerlerle yapacaktır. Java belki bir numara ile. JS şüpheliyim: Optional<Type> a = Optional.empty();.
Joop Eggen

Bu yüzden, bir dolaylı ve potansiyel nullya da boş durumdan , iki nesneye eklenmiş nesnede bazı ekstra yöntemlere geçtik . Bu oldukça başarılı.
Deduplicator

0

CAR Hoare, "milyar dolarlık hatasını" boşa çağırdı. Ancak, çözümün "hiçbir yerde boş bırakma" olmadığını, "bunun yerine" varsayılan olarak boşaltılamaz işaretçileri ve yalnızca semantik olarak gerekli olan yerlerde boş bıraktıklarını "düşündüğünü not etmek önemlidir.

Yanıltısını tekrarlayan dillerde null sorunu, bir işlevin geçersiz olmayan verileri beklediğini söyleyemeyeceğinizdir; Bu dilde temelde ifade edilemez. Bu, birçok gereksiz gereksiz boşaltma kazan plakasını dahil etmeye zorlar ve boş bir kontrolü unutmak yaygın bir hata kaynağıdır.

Bu temel ifade eksikliğini gidermek için bazı topluluklar (örneğin Scala topluluğu) boş kullanmaz. Scala’da null değerinde bir tür istersenizT argümanı Option[T]alırsınız ve null değerine sahip olmayan bir değer istiyorsanız, sadece bir değer alırsınız T. Birisi kodunuza boş geçerse, kodunuz patlar. Ancak, çağrı kodunun buggy kodu olduğu düşünülmektedir. Optiongenel boş işlem kalıpları .map(f)ya da gibi kütüphane fonksiyonlarına getirildiği için boş için oldukça güzel bir alternatif .getOrElse(someDefault).

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.