Başka bloklar kod karmaşıklığını artırır mı? [kapalı]


18

İşte çok basitleştirilmiş bir örnek . Bu mutlaka dile özgü bir soru değildir ve işlevin yazılabileceği diğer birçok yolu ve bu konuda yapılabilecek değişiklikleri göz ardı etmenizi rica ediyorum. . Renk benzersiz tiptedir

string CanLeaveWithoutUmbrella()
{
    if(sky.Color.Equals(Color.Blue))
    {
        return "Yes you can";
    }
    else
    {
        return "No you can't";
    }
}

Bir çok insanla tanıştım, ReSharper ve bu adam (yorumu bana bir süredir sormak istediğimi hatırlattı) elsebu bırakarak bloğu kaldırmak için kodu yeniden düzenlemenizi tavsiye ediyor:

(Çoğunluğun söylediklerini hatırlayamıyorum, bunu başka türlü sormamış olabilirim)

string CanLeaveWithoutUmbrella()
{
    if(sky.Color.Equals(Color.Blue))
    {
        return "Yes you can";
    }
    return "No you can't";
}

Soru:else Bloğu dahil etmeyerek karmaşıklıkta bir artış var mı ?

Her elseiki bloktaki kodun doğrudan ilişkili olduğu gerçeğini belirterek , daha doğrudan devlet niyetinin izlenimi altındayım .

Buna ek olarak, özellikle sonraki bir tarihte kodlama değişikliklerinden sonra mantıktaki ince hataları önleyebileceğimi görüyorum.

Benim sadeleştirilmiş örneğimin bu varyasyonunu al ( orBu bilerek basitleştirilmiş bir örnek olduğu için operatörün gerçeğini yok saymak ):

bool CanLeaveWithoutUmbrella()
{
    if(sky.Color != Color.Blue)
    {
        return false;
    }
    return true;
}

Birisi if, ilk koşuldan hemen sonra ilk koşulun kendi durumuna bir kısıtlama koymasını hemen bilmeden bir koşula dayalı yeni bir blok ekleyebilir .

Bir elseblok mevcut olsaydı, yeni koşulu ekleyen kişi, elsebloğun içeriğini taşımaya zorlanırdı (ve bir şekilde üzerinde parlarlarsa sezgisel tarama, kodun erişilemez olduğunu gösterir, biri diğerini ifkısıtlıyorsa) .

Elbette, spesifik örneğin yine de tanımlanması gereken başka yollar da vardır, hepsi bu durumu önler, ancak bu sadece bir örnektir.

Verdiğim örneğin uzunluğu bunun görsel yönünü çarpıtabilir, bu nedenle parantez içine alınan alanın, yöntemin geri kalan kısmı için nispeten önemsiz olduğunu varsayalım.

Başka bir bloğun atlanmasına katıldığım bir durumdan bahsetmeyi unuttum ve bir ifblok kullanırken null-check (veya başka herhangi bir koruma) gibi aşağıdaki tüm kodlar için mantıksal olarak tatmin edilmesi gereken bir kısıtlama uygulamak için kullanıyorum. .


Gerçekte, bir "dönüş" ile bir "if" ifadesi olduğunda, tüm vakaların>% 50'sinde "koruma bloğu" olarak görülebilir. Bu yüzden yanılgınızın burada bir "bekçi bloğu" nun istisnai durum olduğunu ve örneğin normal durum olduğunu düşünüyorum.
Doc Brown

2
@AssortedTrailmix: Yukarıdaki gibi bir davanın, elsemaddeyi yazarken daha okunabilir olabileceğini kabul ediyorum (benim zevkime göre, gereksiz parantezleri terk ederken daha da okunabilir olacaktır. Ama bence örnek iyi seçilmiş değil, çünkü Yukarıdaki durum return sky.Color == Color.Blue(eğer / else olmadan) yazardım Bool'dan farklı bir dönüş türüne sahip bir örnek muhtemelen bunu daha açık hale getirecektir
Doc Brown

1
yukarıdaki yorumlarda belirtildiği gibi, önerilen örnek çok basitleştirilmiş ve spekülatif cevapları davet ediyor. Sorunun kısmına gelince ile başlar o "Birisi şimdi yeni bir blok ... eğer ekleyebilir" örneğin bkz önce, bu sorular ve yanıtlar edilmiş birçok kez birden fazla koşul kontrol yaklaşımlar? ve buna bağlı birden fazla soru.
gnat

1
DRY prensibi ile başka blokların ne ilgisi olduğunu göremiyorum. DRY, soyutlama ve işlevler, yöntemler ve nesneler biçiminde yaygın olarak kullanılan koda yapılan göndermelerle, sorduğunuzdan daha fazlasını yapar. Sorunuz kod okunabilirliği ve muhtemelen kurallar veya deyimler ile ilgilidir.
Shashank Gupta

2
Yeniden açmak için oylama. Bu soruya verilecek iyi yanıtlar özellikle fikir temelli değildir. Bir soruda verilen örnek yetersizse, onu düzenleyerek iyileştirmek, aslında doğru olmayan bir nedenden dolayı kapatmak için oy vermemek, yapılması makul bir şey olacaktır.
Michael Shaw

Yanıtlar:


27

Benim görüşüme göre, başka açık blok tercih edilir. Bunu gördüğümde:

if (sky.Color != Blue) {
   ...
}  else {
   ...
}

Karşılıklı özel seçeneklerle uğraştığımı biliyorum. Söyleyebilmek için if bloklarının içinde ne olduğunu okumama gerek yok.

Bunu gördüğümde:

if (sky.Color != Blue) {
   ...
} 
return false;

İlk bakışta, ne olursa olsun yanlış döner ve isteğe bağlı bir yan etkisi vardır, gökyüzü mavi değildir.

Gördüğüm gibi, ikinci kodun yapısı kodun gerçekte ne yaptığını yansıtmıyor. Bu kötü. Bunun yerine, mantıksal yapıyı yansıtan ilk seçeneği seçin. Mantıksal akışı bilmek için her blokta dönüş / kırılma / devam mantığını kontrol etmek istemiyorum.

Neden biri diğerini tercih ederse benim için bir gizemdir, umarım birisi karşıt pozisyonu alacak ve cevaplarıyla beni aydınlatacaktır.

Başka bir bloğun atlanmasına katıldığım bir durumdan bahsetmeyi unuttum ve bir null blok (null check (veya başka korumalar) gibi aşağıdaki tüm kodlar için mantıksal olarak tatmin edilmesi gereken bir kısıtlama uygulamak için kullanılıyorsa ).

Mutlu yoldan ayrılmanız durumunda koruma koşullarının iyi olduğunu söyleyebilirim. Normal yürütmenin devam etmesini engelleyen bir hata veya hata oluştu. Bu durumda, bir istisna atmanız, bir hata kodu veya diliniz için uygun olanı döndürmeniz gerekir.

Bu cevabın orijinal versiyonundan kısa bir süre sonra, projemde şöyle bir kod bulundu:

Foobar merge(Foobar left, Foobar right) {
   if(!left.isEmpty()) {
      if(!right.isEmpty()) {
          Foobar merged = // construct merged Foobar
          // missing return merged statement
      }
      return left;
   }
   return right;
}

Dönüşü başkalarının içine koymamakla, bir iade ifadesinin eksik olduğu göz ardı edildi. Başka istihdam edilmiş olsaydı, kod derlenemezdi bile. (Tabii ki, sahip olduğum çok daha büyük endişe, bu kod üzerinde yazılı testlerin bu sorunu tespit etmemek için oldukça kötü olmasıdır.)


Bununla ilgili düşüncelerimi özetliyor, böyle düşünen tek kişi ben olmadığım için mutluyum. Programcıları, araçları ve elsebloğun kaldırılmasını tercih eden IDE'lerle çalışıyorum (sadece bir kod tabanı için kurallarla satır içi tutmak için yapmak zorunda kaldığımda rahatsız edici olabilir). Ben de karşıt noktayı burada görmek istiyorum.
Selali Adobor

1
Ben buna bağlıyım. Bazı zamanlar açık olan OP'nin bahsettiği ince mantık hatalarını tetiklemesi pek mümkün olmadığı için çok fazla kazanmıyor. Ama çoğunlukla katılıyorum ve bazen } // elsediğerlerinin normalde ikisi arasında bir uzlaşma olarak gideceği gibi bir şey yapacağım.
Telastyn

3
@Telastyn, ama diğerini atlamaktan ne kazanıyorsun? Faydasının birçok durumda çok az olduğu konusunda hemfikirim, ancak ufak bir yarar için bile buna değer olduğunu düşünüyorum. Kesinlikle, kod olabileceği zaman bir yorum yapmak bana garip geliyor.
Winston Ewert

2
Ben OP ile aynı yanlışlığa sahip olduğunu düşünüyorum - "dönüş" ile "çoğunlukla bir bekçi bloğu olarak görülebilir eğer, bu yüzden burada istisnai durum tartışırken, daha sık güvenlik blokları durumda IMHO olmadan daha okunabilir "Başka".
Doc Brown

... yani yazdığın yanlış değil, ama IMHO aldığın pek çok oyuna değmez.
Doc Brown

23

elseBulduğum bloğun kaldırılmasının temel nedeni aşırı girinti. elseBlokların kısa devre yapması çok daha düz bir kod yapısı sağlar.

Birçok ififade esasen koruyucudur. Boş göstergelerin ve diğer "bunu yapma!" hatalar. Ve mevcut fonksiyonun hızlı bir şekilde sonlandırılmasına yol açarlar. Örneğin:

if (obj === NULL) {
    return NULL;
}
// further processing that now can assume obj attributes are set

Şimdi burada bir elsemadde çok makul görünebilir :

if (obj === NULL) {
    return NULL;
}
else if (obj.color != Blue) {
   // handle case that object is not blue
}

Gerçekten de yaptığınız tek şey buysa, yukarıdaki örnekten çok daha fazla girintili değildir. Ancak, bu gerçek, çok seviyeli veri yapılarıyla (JSON, HTML ve XML gibi ortak formatları işlerken her zaman meydana gelen bir durum) nadiren yaptığınız şeydir. Dolayısıyla, belirli bir HTML düğümünün tüm alt öğelerinin metnini değiştirmek istiyorsanız, şunları söyleyin:

elements = tree.xpath(".//p");
if (elements === NULL) {
    return NULL;
}
p = elements[0]
if ((p.children === NULL) or (p.children.length == 0)) {
    return NULL;
}
for (c in p.children) {
    c.text = c.text.toUpperCase();
}
return p;

Muhafızlar, kodun girintisini arttırmaz. Bir elsecümle ile, tüm gerçek çalışma sağa doğru ilerlemeye başlar:

elements = tree.xpath(".//p");
if (elements === NULL) {
    return NULL;
}
else {
    p = elements[0]
    if ((p.children === NULL) or (p.children.length == 0)) {
        return NULL;
    }
    else {
        for (c in p.children) {
            c.text = c.text.toUpperCase();
        }
        return p;
    }
}

Bu önemli bir sağa doğru harekete başlıyor ve bu sadece iki koruma koşulu ile oldukça önemsiz bir örnek. Her ek koruma başka bir girinti seviyesi ekler. Gerçek kod Ben işleme XML yazdım veya detaylı JSON beslemeleri tüketmek kolayca 3, 4 veya daha fazla koruma koşullarını yığın olabilir. Her zaman kullanırsanız, else4, 5 veya 6 seviye girintilersiniz. Belki daha fazla. Ve bu kesinlikle bir kod karmaşıklığı hissine katkıda bulunur ve neyin neyle uyumlu olduğunu anlamak için daha fazla zaman harcar. Hızlı, düz, erken çıkış tarzı bu "fazla yapı" nın bazılarını ortadan kaldırır ve daha basit görünür.

Ek Bu yanıt üzerine yorumlar beni BOŞ / boş elleçleme olduğunu açıkça edilmiş olmayabilir fark ettirdi değil bekçi koşullar için tek nedeni. Yakın değil! Bu basit örnek NULL / boş işleme üzerine odaklanırken ve başka nedenler içermese de, XML ve AST gibi derin yapıların "alakalı" içerik için araştırılması, genellikle alakasız düğümleri ayıklamak ve ilginç olmayan uzun bir dizi özel teste sahiptir. vakalar. Bir dizi "bu düğüm ilgili değilse, geri dönüş" testleri NULL / boş korumaların yaptığı gibi sağa doğru kaymaya neden olur. Ve pratikte, daha sonraki alaka düzeyi testleri, aranan daha derin veri yapıları için genellikle NULL / boş korumalarla birleştirilir - sağa doğru sürüklenme için bir çift vagon.


2
Bu ayrıntılı ve geçerli bir cevap, ama bunu soruya ekleyeceğim (İlk başta aklımdan kaçtı); Her zaman elsegereksiz bir blok bulduğumda , null-check (veya diğer korumalar) gibi aşağıdaki tüm kodlar için mantıksal olarak tatmin edilmesi gereken ifbir kısıtlama uygulamak için bir blok kullanırken bir "istisna" vardır .
Selali Adobor

@AssortedTrailmix Cümlede rutin olarak erken çıkış yapabileceğiniz durumları then(ardışık koruma ifadeleri gibi) hariç tutarsanız , o zaman bu elsemaddeden kaçınmanın özel bir değeri olmadığına inanıyorum . Gerçekten de, netliği azaltacak ve potansiyel olarak tehlikeli olacaktır (orada olan / olması gereken alternatif yapıyı basitçe belirtmemek suretiyle).
Jonathan Eunice

Mutlu yoldan ayrıldıktan sonra atmak için koruma koşullarını kullanmak mantıklı. Ancak, XML / JSON işleme durumunda da ilk önce bir şemaya göre girişi doğrularsanız, daha iyi hata mesajları ve daha temiz kodlar elde ettiğinizi görüyorum.
Winston Ewert

Bu, kaçınılması gereken vakaların mükemmel bir açıklamasıdır.
Chris Schiffhauer

2
Bunun yerine aptal NULL üretmek için API sarılmış olurdu.
Winston Ewert

4

Bunu gördüğümde:

if(something){
    return lamp;
}
return table;

Ortak bir deyim görüyorum . Kafamda şu anlama gelen ortak bir desen :

if(something){
    return lamp;
}
else return table;

Bu programlamada çok yaygın bir deyim olduğu için, bu tür kodları görmeye alışkın olan programcı, her gördüklerinde başlarında örtük bir 'çeviri' yapar, bu onu doğru anlama 'dönüştürür'.

Açık olana ihtiyacım yok else, kafam benim için 'oraya koyar' çünkü deseni bir bütün olarak tanıdı . Tüm ortak modelin anlamını anlıyorum, bu yüzden açıklığa kavuşturmak için küçük detaylara ihtiyacım yok.

Örneğin, aşağıdaki metni okuyun:

resim açıklamasını buraya girin

Bunu okudun mu?

İlkbaharda Paris'i seviyorum

Eğer öyleyse, yanılıyorsunuz. Metni tekrar okuyun. Aslında yazılan şey

Ben Paris'i seviyorum bahar

Orada iki metinde "" kelimeler. Peki neden bu ikisinden birini özledin?

Çünkü beyniniz ortak bir kalıp gördü ve hemen bilinen anlamına çevirdi. Anlamını anlamak için her şeyi ayrıntılı olarak okumasına gerek yoktu, çünkü onu gördükten sonra deseni zaten tanıdı . Bu yüzden ekstra "the " i görmezden geldi .

Yukarıdaki deyimle aynı şey. Bir sürü kod okudum Programcılar bu görmeye alışık deseni arasında if(something) {return x;} return y;. elseBunun anlamını anlamak için bir sünnetçiye ihtiyaç duymazlar , çünkü beyinleri 'onlar için oraya koyar'. Onlar bilinen bir anlamı olan bir model olarak tanımıyor: "Ne Kapanış ayracı peşinde örtük olarak sadece çalışacaktır elseönceki ait if".

Bence elsebu gereksiz. Ancak daha okunaklı görünenleri kullanın.


2

Kodda görsel karmaşa eklerler, bu yüzden evet, karmaşıklık ekleyebilirler.

Bununla birlikte, bunun tersi de geçerlidir, kod uzunluğunu azaltmak için aşırı yeniden düzenleme de karmaşıklık ekleyebilir (elbette bu basit durumda değil).

elseBloğun niyetini belirten ifadeye katılıyorum . Ama benim sonucum farklı, çünkü bunu başarmak için kodunuza karmaşıklık katıyorsunuz.

İfadenize, mantıktaki ince hataları önlemenize izin verdiğine katılmıyorum.

Bir örnek görelim, şimdi sadece Gökyüzü Mavi ve yüksek Nem varsa, Nem yüksek değil veya Gökyüzü Kırmızı ise doğru dönmelidir. Ama sonra, bir ayracı karıştırıp yanlış yere yerleştirirsiniz else:

bool CanLeaveWithoutUmbrella() {
    if(sky.Color == Color.Blue)
    {
        if (sky.Humidity == Humidity.High) 
        {
            return true;
        } 
    else if (sky.Humidity != Humidity.High)
    {
        return true;
    } else if (sky.Color == Color.Red) 
    {
            return true;
    }
    } else 
    {
       return false;
    }
}

Üretim kodunda bu tür aptalca hatalar gördük ve tespit edilmesi çok zor olabilir.

Aşağıdakileri öneririm:

Bunu okumayı daha kolay buluyorum, çünkü varsayılanın bir bakışta olduğunu görebiliyorum false.

Ayrıca, yeni bir madde eklemek için bir bloğun içeriğini taşımaya zorlama fikri hatalara eğilimlidir. Bu bir şekilde açık / kapalı prensibi ile ilgilidir (kod uzatma için açık, ancak değişiklik için kapalı olmalıdır). Mevcut kodu değiştirmeye zorluyorsunuz (örn. Kodlayıcı parantez dengelemesinde bir hata verebilir).

Son olarak, insanları doğru olduğunu düşündüğünüz önceden belirlenmiş bir şekilde cevaplamaya yönlendiriyorsunuz. Örneğin, çok basit bir örnek sunuyorsunuz, ancak daha sonra insanların bunu dikkate almaması gerektiğini belirtiyorsunuz. Ancak, örneğin basitliği tüm soruyu etkiler:

  • Dava sunulan dava kadar basitse, cevabım hiç bir if elsecümleyi atlamak olacaktır .

    dönüş (sky.Color == Color.Blue);

  • Dava biraz daha karmaşıksa, çeşitli maddelerle, cevap verirdim:

    bool CanLeaveWithoutUmbrella () {

    if(sky.Color == Color.Blue && sky.Humidity == Humidity.High) {
        return true;
    } else if (sky.Humidity != Humidity.High) {
        return true;
    } else if (sky.Color == Color.Red) {
        return true;
    }
    
    return false;
    

    }

  • Durum karmaşıksa ve tüm yan tümceler doğru dönmezse (belki bir çift döndürürler) ve bazı kesme noktası veya loggin komutunu vermek istiyorum, şöyle bir şey düşünürdüm:

    double CanLeaveWithoutUmbrella() {
    
        double risk = 0.0;
    
        if(sky.Color == Color.Blue && sky.Humidity == Humidity.High) {
            risk = 1.0;
        } else if (sky.Humidity != Humidity.High) {
            risk = 0.5;
        } else if (sky.Color == Color.Red) {
            risk = 0.8;
        }
    
        Log("value of risk:" + risk);
        return risk;
    

    }

  • Bir şey döndüren bir yöntemden bahsetmiyorsak, bunun yerine bazı değişkenleri ayarlayan veya bir yöntemi çağıran if-else bloğu varsa, evet, son bir elsecümle eklerdim.

Bu nedenle, örneğin sadeliği de dikkate alınması gereken bir faktördür.


Başkalarının yaptığı aynı hatayı yaptığınızı ve örneği biraz fazla değiştirdiğinizi, böylece yeni bir sorunu incelediğinizi hissediyorum, ancak bir saniye ayırıp örneğinize ulaşma sürecini incelemem gerekiyor, bu yüzden şimdilik görünüyor benim için geçerli. Ve bir yan not, bu açık / kapalı prensibi ile ilgili değildir . Kapsam, bu deyimi uygulamak için çok dar. Ancak, daha yüksek bir düzeyde uygulanmasının, sorunun tüm yönünü ortadan kaldıracağını belirtmek ilginçtir ( işlevde herhangi bir değişiklik yapılması gerekliliğini kaldırarak ).
Selali Adobor

1
Ancak, aşırı basitleştirilmiş örnek ekleme maddelerini değiştiremezsek, nasıl yazıldığını değiştiremezsek veya üzerinde herhangi bir değişiklik yapamazsak, bu sorunun yalnızca bu kesin kod satırlarıyla ilgili olduğunu ve artık genel bir soru olmadığını düşünmelisiniz. Bu durumda, tamamen haklısınız, diğer maddeyi herhangi bir karmaşıklık eklemiyor (ya da kaldırmıyor) çünkü başlangıçta herhangi bir karmaşıklık yoktu. Ancak adil değilsiniz, çünkü yeni hükümlerin eklenebileceği fikrini öneren sizsiniz.
FranMowinckel

Yan not ettiğim gibi, bunun iyi bilinen açık / kapalı prensibi ile ilgili olduğunu belirtmiyorum. İnsanların önerdiğiniz gibi kodunuzu değiştirmesine yol açma fikrinin hatalara eğilimli olduğunu düşünüyorum. Bu fikri sadece bu prensipten alıyorum.
FranMowinckel

Düzenlemeleri
bekle

1

Açıklanan if-else vakası daha karmaşık olmasına rağmen, çoğu (ancak hepsi değil) pratik durumda çok önemli değildir.

Yıllar önce havacılık endüstrisi için kullanılan bir yazılım üzerinde çalışırken (bir sertifikasyon sürecinden geçmek zorunda kaldı), sizinki ortaya çıkan bir soruydu. Kod karmaşıklığını artırdığı için bu 'else' ifadesine finansal bir maliyet olduğu ortaya çıktı.

İşte nedeni.

'Else' varlığı, değerlendirilmesi gereken örtük bir 3. durum yarattı - ne 'if' ne de 'else' olgusu. Düşünüyor olabilirsiniz (o zamanki gibi) WTF?

Açıklama böyle gitti ...

Mantıksal bir bakış açısından, sadece iki seçenek vardır - 'if' ve 'else'. Ancak, sertifikalandırdığımız derleyicinin oluşturduğu nesne dosyasıydı. Bu nedenle, bir 'başka' olduğunda, oluşturulan dallanma kodunun doğru olduğunu ve gizemli bir 3. yolun ortaya çıkmadığını doğrulamak için bir analiz yapılması gerekiyordu.

Bunu sadece 'if' olan ve 'else' olmayan durumla karşılaştırın. Bu durumda, yalnızca iki seçenek vardır - 'if' yolu ve 'if olmayan' yol. Değerlendirilecek iki vaka üçten daha az karmaşıktır.

Bu yardımcı olur umarım.


bir nesne dosyasında, her iki durumda da özdeş jmps olarak görüntülenmez mi?
Winston Ewert

@WinstonEwert - Bunların aynı olmasını bekleriz. Bununla birlikte, ne kadar üst üste geldiklerine bakılmaksızın, oluşturulan ve oluşturulması beklenen şey iki farklı şeydir.
Sparky

(Sanırım SE yorumumu yedi ...) Bu çok ilginç bir cevap. Ben onu gösterir durum biraz niş olduğunu söyleyebilirim rağmen, bazı araçlar ikisi arasında bir fark (I cyclomatic karmaşıklığını görüyoruz akış, hiç fark göreceğinizin dayalı metrik Hatta en yaygın kod bulacağını neleri gösterir.
Selali Adobor

1

Kodun en önemli amacı, taahhüt edildiği gibi anlaşılabilir olmaktır (kolayca yeniden düzenlenmenin aksine, yararlı ancak daha az önemlidir). Bunu göstermek için biraz daha karmaşık bir Python örneği kullanılabilir:

def value(key):
    if key == FROB:
        return FOO
    elif key == NIK:
        return BAR
    [...]
    else:
        return BAZ

Bu oldukça açık - bir caseifade veya sözlük aramaya eşdeğerdir return foo == bar:

KEY_VALUES = {FROB: FOO, NIK: BAR, [...]}
DEFAULT_VALUE = BAZ

def value(key):
    return KEY_VALUES.get(key, default=DEFAULT_VALUE)

Bu daha açıktır, çünkü jeton sayısı daha yüksek olsa da (iki anahtar / değer çiftli orijinal kod için 32'ye 24), fonksiyonun anlambilimi artık açıktır: Bu sadece bir aramadır.

(Bunun yeniden düzenleme için sonuçları vardır - eğer bir yan etkiye key == NIKsahip olmak istiyorsanız, üç seçeneğiniz vardır:

  1. if/ elif/ Stiline geri dönün elseve key == NIKkasaya tek bir satır ekleyin .
  2. Arama sonucunu bir değere kaydedin ve dönmeden önce özel durum için bir ififade ekleyin value.
  3. Arayana bir ififade koy .

Şimdi arama işlevinin neden güçlü bir sadeleştirme olduğunu görüyoruz: Üçüncü seçeneği açıkça en basit çözüm haline getiriyor, çünkü ilk seçenekten daha küçük bir fark yaratmanın yanı sıra , tek bir şey yaptığından emin olan valuetek şey. )

OP'ın koduna geri dönecek olursak, ben bu karmaşıklığı için bir kılavuz olarak hizmet verebilir düşünüyorum else: tabloların Kodu açık olarak elseobjektif daha karmaşık açıklamada, ancak daha önemli yapar olup olmadığıdır semantik kod açık ve basit. Ve her bir kod parçasının farklı bir anlamı olduğundan, duruma göre cevaplanması gerekir.


Arama tablonuzun basit anahtar kasasının yeniden yazılmasını seviyorum. Ve bunun tercih edilen bir Python deyimi olduğunu biliyorum. Bununla birlikte, pratikte, çok yönlü koşulların (aka caseveya switchifadeler) daha az homojen olduğunu düşünüyorum. Birkaç seçenek sadece düz değer döndürmeleridir, ancak daha sonra bir veya iki durumun ekstra işlemeye ihtiyacı vardır. Arama stratejisinin uygun olmadığını keşfettiğinizde, tamamen farklı bir if elif... elsesözdiziminde yeniden yazmanız gerekir .
Jonathan Eunice

Bu yüzden aramanın genellikle bir astar veya bir işlev olması gerektiğini düşünüyorum, böylece arama sonucunun etrafındaki mantık, ilk etapta arama mantığından ayrılır.
l0b0

Bu soru kesinlikle belirtilmesi ve akılda tutulması gereken soruya daha üst düzey bir bakış getiriyor, ancak kendi duruşunuzda genişleyebildiğiniz konusunda yeterince kısıtlama olduğunu hissediyorum
Selali Adobor

1

Ne tür bir ififade kullandığınıza bağlı olduğunu düşünüyorum . Bazı ififadelere ifade olarak bakılabilirken, diğerleri yalnızca kontrol akışı ifadeleri olarak görülebilir.

Örneğin bana bir ifade gibi geliyor. C-benzeri dillerde, üçlü operatör ?:bir ififadeye çok benzer , ancak bir ifadedir ve diğer kısım atlanamaz. Bir ifadede başka bir dalın atlanamayacağı anlamlıdır, çünkü ifadenin her zaman bir değeri olmalıdır.

Üçlü işleci kullanarak, örneğiniz şöyle görünecektir:

bool CanLeaveWithoutUmbrella()
{
    return (sky.Color == Color.Blue)
               ? true
               : false;
}

Boolean bir ifade olduğu için, gerçekten de basitleştirilmelidir.

bool CanLeaveWithoutUmbrella()
{
    return (sky.Color == Color.Blue);
}

Başka bir açık cümle eklemek niyetinizi daha net hale getirir. Muhafızlar bazı durumlarda mantıklı olabilir, ancak ikisi de istisnai veya olağandışı olan iki olası değer arasından seçim yaparken yardımcı olmazlar.


+1, OP, yukarıda gösterdiğiniz şekilde daha iyi yazılması gereken patolojik bir vakayı tartışan IMHO'dur. İçin çok daha sık vaka "eğer" "dönüş" ile olan deneyimlerime "bekçi" harfini tıklayın.
Doc Brown

Bunun neden devam ettiğini bilmiyorum, ama insanlar sorunun ilk paragrafını görmezden geliyorlar. Aslında, hepiniz açıkça kullanmamamı söylediğim tam kod satırını kullanıyorsunuz. I ask that you ignore the many other ways the function can be written, and changes that can be made to it. (I know most people are itching to write return sky.Color == Color.Blue.)
Selali Adobor

Ve son sorunuzu tekrar okuduğunuzda, sorunun amacını yanlış anlamışsınız gibi görünüyor.
Selali Adobor

Pratik olarak basitleştirilmek için yalvaran bir örnek kullandınız. İlk paragrafınızı okudum ve dikkat ettim, bu yüzden ilk kod bloğum, o örneği yapmak için doğrudan en iyi şekilde atlamak yerine orada. Ben (veya başka birinin) sorunuzun amacını yanlış anladığını düşünüyorsanız, niyetinizi netleştirmek için belki de düzenlemelisiniz.
Michael Shaw

Bunu düzenlerdim, ama yaptığınız kodun tam satırını kullandığım ve "bunu yapma" dediğiniz için daha net hale nasıl getireceğimi bilemezdim . Kodu yeniden yazmanın ve soruyu kaldırmanın sonsuz yolları var,
hepsini kapatamıyorum

1

Bu argümanda düşünülmesi gereken bir diğer şey, her yaklaşımın teşvik ettiği alışkanlıklardır.

  • eğer kodlama örneğini dallar açısından yeniden / eğer yeniden şekillendirirse. Dediğiniz gibi, bazen bu açıklık iyidir. Gerçekten iki olası yürütme yolu var ve bunu vurgulamak istiyoruz.

  • Diğer durumlarda, yalnızca bir yürütme yolu ve daha sonra programcıların endişelenmesi gereken tüm bu olağanüstü şeyler vardır. Bahsettiğiniz gibi, koruyucu hükümler bunun için harikadır.

  • Elbette, if / else zincirini terk etmeyi ve bir case / switch deyimi veya polimorfizm kullanmayı genellikle teşvik ettiğimiz 3 veya daha fazla vaka (n) vardır.

Burada aklıma gelen rehber ilke, bir yöntemin veya fonksiyonun sadece bir amacı olması gerektiğidir. İf / else veya switch ifadesine sahip herhangi bir kod yalnızca dallanma içindir. Bu yüzden saçma derecede kısa (4 satır) olmalı ve sadece doğru yönteme yetki vermeli veya bariz sonuç üretmelidir (örneğin örnek). Kodunuz bu kadar kısa olduğunda, bu birden fazla dönüşü kaçırmak zor :) "Zararlı sayılır" gibi, herhangi bir dallanma ifadesi kötüye kullanılabilir, bu nedenle başka ifadelere eleştirel düşünce koymak genellikle buna değer. Bahsettiğiniz gibi, sadece başka bir bloğa sahip olmak kodun toplanması için bir yer sağlar. Siz ve ekibiniz bunun hakkında ne hissettiğinize karar vermeniz gerekecek.

Aracın gerçekten şikayet ettiği şey, if bloğunun içinde bir dönüş / kırılma / atma olması. Dolayısıyla, bir koruma maddesi yazdınız, ama berbat ettiniz. Aracı mutlu etmeyi seçebilir veya önermesini kabul etmeden "eğlendirebilirsiniz".


Aracın bir kalıbın modeline uyduğu anda bir koruma maddesi olup olmadığını düşünebileceğini hiç düşünmemiştim, muhtemelen durum budur ve olmaması için bir "destekçi grubunun" nedenini açıklar
Selali Adobor

@AssortedTrailmix Doğru, elsesemantik olarak düşünüyorsunuz , kod analiz araçları genellikle yabancı talimatları arar, çünkü genellikle kontrol akışının yanlış anlaşıldığını vurgularlar. elseBir sonra ifbu getiriler bit israf edilir. if(1 == 1)genellikle aynı uyarıyı tetikler.
Steve Jackson

1

Cevabın buna bağlı olduğunu düşünüyorum. Kod örneğiniz (dolaylı olarak işaret ettiğiniz gibi) yalnızca bir koşulun değerlendirmesini döndürür ve en iyi bildiğiniz gibi tek bir ifade olarak temsil edilir.

Başka bir koşul eklemenin kodu netleştirip gizlemediğini belirlemek için IF / ELSE'in neyi temsil ettiğini belirlemeniz gerekir. (Örneğinizde olduğu gibi) bir ifade mi? Eğer öyleyse, bu ifade çıkarılmalı ve kullanılmalıdır. Bu bir koruma koşulu mu? Eğer öyleyse, ELSE gereksiz ve yanıltıcıdır, çünkü iki dalın eşdeğer görünmesini sağlar. Prosedürel polimorfizmin bir örneği mi? Çıkarın. Ön koşulları ayarlıyor mu? O zaman gerekli olabilir.

ELSE'yi dahil etmeye veya ortadan kaldırmaya karar vermeden önce, neyin temsil edileceğine karar verin, bu da mevcut olup olmayacağını size söyleyecektir.


0

Cevap biraz öznel. Bir elseblok, bir kod bloğunun, her iki bloğu da okumak zorunda kalmadan, yalnızca başka bir kod bloğuna çalıştığını belirleyerek okunabilirliğe yardımcı olabilir. Her iki blok nispeten uzunsa, bu yardımcı olabilir. Sahip nerede olsa vakalar vardır ifolmadan ler elses daha okunabilir olabilir. Aşağıdaki kodu birkaç if/elseblokla karşılaştırın:

if(a == b) {
    if(c <= d) {
        if(e != f) {
            a.doSomeStuff();
            c.makeSomeThingsWith(b);
            f.undo(d, e);
            return 9;
        } else {
            e++;
            return 3;
        }
    } else {
        return 1;
    }
} else {
    return 0;
}

ile:

if(a != b) {
    return 0;
}

if(c > d) {
    return 1;
}

if(e != f) {
    e++;
    return 3;
}

a.doSomeStuff();
c.makeSomeThingsWith(b);
f.undo(d, e);
return 9;

İkinci kod bloğu yuvalanmış ififadeleri koruma maddelerine dönüştürür. Bu, girintiyi azaltır ve bazı iade koşullarını daha net hale getirir ("eğer a != bgeri dönersek 0!")


Yorumumda, örneğimde bazı delikler olabileceğine dikkat çekildi, bu yüzden biraz daha ettim.

Daha okunabilir hale getirmek için ilk kod bloğunu burada yazabilirdik:

if(a != b) {
    return 0;
} else if(c > d) {
    return 1;
} else if(e != f) {
    e++;
    return 3;
} else {
    a.doSomeStuff();
    c.makeSomeThingsWith(b);
    f.undo(d, e);
    return 9;
}

Bu kod yukarıdaki her iki bloğa eşdeğerdir, ancak bazı zorluklar ortaya çıkarır. Buradaki elsemadde , if ifadelerini birbirine bağlar . Yukarıdaki koruma maddesi versiyonunda, koruma maddeleri birbirinden bağımsızdır. Yeni bir tane eklemek , mantığın ifsonuncusu ifile geri kalanı arasına yeni bir şey yazmak anlamına gelir . Burada, sadece az miktarda daha fazla bilişsel yük ile de yapılabilir. Ancak fark, yeni koruma maddesinden önce bazı ek mantıkların oluşması gerektiğidir. İfadeler bağımsız olduğunda şunları yapabiliriz:

...
if(e != f) {
    e++;
    return 3;
}

g.doSomeLogicWith(a);

if(!g.isGood()) {
    return 4;
}

a.doSomeStuff();
...

Bağlı if/elsezincir ile bunu yapmak o kadar kolay değildir. Nitekim, almanın en kolay yolu, daha fazla koruma maddesi versiyonuna benzemek için zinciri kırmak olacaktır.

Ama gerçekten, bu mantıklı. if/elseZayıf bir şekilde kullanılması parçalar arasında bir ilişki olduğunu gösterir. Bunu tahmin olabilir a != bnasılsa ilişkilidir c > diçinde if/elsezincir tipleri. Muhafız fıkra versiyonundan görebileceğimiz gibi aslında bu varsayım yanıltıcı olacaktır. Bu, onları yeniden düzenlemek gibi bağımsız yan tümcelerle daha fazlasını yapabileceğimiz anlamına gelir (belki de sorgu performansını optimize etmek veya mantıksal akışı iyileştirmek için). Onları geçtikten sonra da bilişsel olarak görmezden gelebiliriz. Bir In if/elsezinciri, ben arasındaki denklik ilişkisi daha az eminim ave bdaha sonra geri açılır olmaz.

İma edilen ilişki elsederin iç içe örnek kodda da farklıdır. elseTablolar, bağlı oldukları koşullu ayrılır ve bunlar ile ilişkili olan ters Koşullamalar için (ilk elseson bağlı olduğu ifson elsebirinci bağlanmıştır if). Bu, beynimizdeki girintiyi sıralamaya çalışarak, kod boyunca geri gitmemiz gereken bilişsel bir uyumsuzluk yaratır. Biraz parantezle eşleşmeye çalışmak gibi. Girintinin yanlış olması daha da kötüleşir. İsteğe bağlı parantezler de yardımcı olmaz.

Başka bir bloğun atlanmasına katıldığım bir durumdan bahsetmeyi unuttum ve bir null blok (null check (veya başka korumalar) gibi aşağıdaki tüm kodlar için mantıksal olarak tatmin edilmesi gereken bir kısıtlama uygulamak için kullanılıyorsa ).

Bu hoş bir tavizdir, ancak gerçekten herhangi bir cevabı geçersiz kılmaz. Kod örneğinizde bunu söyleyebilirim:

bool CanLeaveWithoutUmbrella()
{
    if(sky.Color != Color.Blue)
    {
        return false;
    }
    return true;
}

böyle bir kod yazmak için geçerli bir yorum "sadece gökyüzü mavi değilse bir şemsiye ile ayrılmalıyız" olabilir. Burada, aşağıdaki kodun çalışması için gökyüzünün mavi olması gerektiğine dair bir kısıtlama vardır. İmtiyazınızın tanımıyla tanıştım.

Gökyüzü rengi siyahsa, berrak bir gece, yani şemsiye gerekli olmadığını söylesem. (Bunu yazmanın daha basit yolları vardır, ancak tüm örneği yazmanın daha basit yolları vardır.)

bool CanLeaveWithoutUmbrella()
{
    if(sky.Color == Color.Blue)
    {
        return true;
    }

    if(sky.Color == Color.Black)
    {
        return true;
    }

    return false;
}

Yukarıdaki daha büyük örnekte olduğu gibi, yeni maddeyi fazla düşünmeden ekleyebilirim. Bir In if/else, o kadar emin ben karışıklık birşeyler, mantık, özellikle daha karmaşık olmayacak olamaz.

Ayrıca basit örneğinizin o kadar basit olmadığını da belirteceğim. İkili olmayan bir değer için yapılan test, tersine çevrilmiş sonuçlarla bu testin tersi ile aynı değildir.


1
Soruya yaptığım düzenleme bu durumu ele alıyor. Bir null kontrol (veya başka herhangi bir koruma) gibi aşağıdaki tüm kodlar için mantıksal olarak yerine getirilmesi gereken bir kısıtlama, elseokunabilirlik için bir bloğun atlanmasının şart olduğunu kabul ediyorum .
Selali Adobor

1
İlk sürümünüzü kavramak zordur, ancak if / else kullanarak bunun gerekli olduğunu düşünmüyorum. Nasıl yazacağımı görün: gist.github.com/winstonewert/c9e0955bc22ce44930fb .
Winston Ewert

@WinstonEwert Yorumlarınıza yanıt için düzenlemelere bakın.
cbojar

Yaptığınız düzenlemede bazı geçerli noktalar var. Ve kesinlikle bekçi hükümlerinin bir yeri olduğunu düşünüyorum. Ama genel olarak, başka maddelerden yanayım.
Winston Ewert

0

Örneğinizi çok basitleştirdiniz. Her iki seçenek de daha büyük duruma bağlı olarak daha okunabilir olabilir: özellikle, durumun iki kolundan birinin anormal olup olmadığına bağlıdır . Size göstereyim: her iki dalın da eşit derecede muhtemel olduğu bir durumda, ...

void DoOneOfTwoThings(bool which)
{
    if (which)
        DoThingOne();
    else
        DoThingTwo();
}

... daha okunabilir ...

void DoOneOfTwoThings(bool which)
{
    if (which) {
        DoThingOne();
        return;
    }
    DoThingTwo();
}

... çünkü birincisi paralel bir yapı sergiliyor ve ikincisi bunu yapmıyor. Ancak, işlevin büyük kısmı bir göreve atandığında ve önce bazı önkoşulları kontrol etmeniz yeterlidir, ...

void ProcessInputOfTypeOne(String input)
{
    if (InputIsReallyTypeTwo(input)) {
        ProcessInputOfTypeTwo(input);
        return;
    }
    ProcessInputDefinitelyOfTypeOne(input);

}

... daha okunabilir ...

void ProcessInputOfTypeOne(String input)
{
    if (InputIsReallyTypeTwo(input))
        ProcessInputOfTypeTwo(input);
    else
        ProcessInputDefinitelyOfTypeOne(input);
}

Kasten çünkü ... değil paralel yapıyı kurma var sinyal almadığı için burada "gerçekten iki tip" bir gelecek okuyucuya bir ipucu sağlar olduğu anormal . (Gerçek hayatta ProcessInputDefinitelyOfTypeOneayrı bir işlev olmaz, bu yüzden fark daha da keskin olur.)


İkinci dava için daha somut bir örnek seçmek daha iyi olabilir. Buna anında tepkim, "Devam edip yine de işlerseniz anormal olamaz."
Winston Ewert

@ WinstonEwert anormal belki de yanlış terimdir. Ama Zack ile aynı fikirdeyim, eğer bir varsayılan (durum1) ve bir istisnanız varsa, » if-> İstisnai yapın ve« erken dönüş stratejisi olarak bırakın . Varsayılanın daha fazla kontrol içerdiği kodu düşünün, önce istisnai durumu ele almak daha hızlı olacaktır.
Thomas Junk

Bu, bahsettiğim davaya düşüyor gibi görünüyor when using an if block to apply a constraint that must be logically satisfied for all following code, such as a null-check (or any other guards). Mantıksal olarak, herhangi bir çalışma ProcessInputOfTypeOne, gerçeğe bağlıdır !InputIsReallyTypeTwo(input), bu yüzden bunu normal işlemimizin dışında tutmamız gerekir. Normalde ProcessInputOfTypeTwo(input);gerçektenthrow ICan'tProccessThatException benzerlik daha belirgin kılacak olan.
Selali Adobor

@WinstonEwert Belki bunu daha iyi ifade edebilirdim, evet. Jetonlayıcıları elle kodlarken çok fazla ortaya çıkan bir durum düşünüyordum: CSS'de, örneğin, " u+" karakter dizisi genellikle "unicode-range" jetonu tanıtır, ancak bir sonraki karakter onaltılık bir rakam değilse, daha sonra bunun yerine 'u' tanımlayıcı olarak yedeklenmeli ve işlenmelidir. Bu nedenle, ana tarayıcı döngüsü bir şekilde "unicode-aralıklı bir jetonu tara" işlevini gönderir ve "... bu alışılmadık özel durumdaysa, yedekleme yapın, bunun yerine tanımlayıcı taraması alt yordamını çağırın."
zwol

@AssortedTrailmix Düşündüğüm örnek, istisnaların kullanılamayacağı eski bir kod tabanından gelmemiş olsa bile, bu bir hata koşulu değildir , yalnızca çağıran kod ProcessInputOfTypeOnebazen kesin olmayan ancak hızlı bir denetim kullanıyorsa yerine iki tür yakalar.
zwol

0

Evet, karmaşıklıkta bir artış var, çünkü diğer fıkra fazla . Bu nedenle, kodu yalın ve ortalama tutmak için dışarıda bırakmak daha iyidir. Gereksiz thisniteleyicileri (Java, C ++, C #) atlamak ve returnifadelerde parantezleri atlamak vb. İle aynı akor üzerinde.

İyi bir programcı "ne ekleyebilirim?" harika bir programcı "neyi kaldırabilirim?"


1
elseBloğun ihmal edildiğini gördüğümde , eğer tek satırda açıklanırsa (ki bu çoğu zaman değil) genellikle bu tür bir akıl yürütme ile olur, bu yüzden +1 gördüğüm "varsayılan" argümanı sunmak için, ama ben bunu yeterince güçlü bir akıl yürütme olarak bulur A good programmer things "what can I add?" while a great programmer things "what can I remove?".bir çok insanın dikkatlice düşünülmeden fazla uzandığı ortak bir atasözü gibi görünüyor ve ben şahsen bunu böyle bir durum olarak görüyorum.
Selali Adobor

Evet, sorunuzu okurken hemen kararınızı verdiğinizi hissettim, ama onaylamak istedim. Bu cevap açıkça istediğiniz şey değil, bazen aynı fikirde olmadığınız fikirleri dikkate almak önemlidir. Belki de bir şey var mı?
vidstige

-1

Bu davadaki fikrimi değiştirerek fark ettim.

Bir yıl önce bu soruyu sorduğumda, şöyle bir şey cevaplardım:

»Sadece bir tane olmalı entryexit Bir yöntem ve bir « Ve bunu göz önünde bulundurarak, kodu yeniden düzenlemeyi öneririm:

bool CanLeaveWithoutUmbrella()
{
    bool result

    if(sky.Color == Color.Blue)
    {
        result = true;
    }
    else
    {
        result = false;
    }

    return result;
}

İletişim açısından bakıldığında ne yapılması gerektiği açıktır . Ifbir şey var, sonucu bir şekilde , else başka bir şekilde manipüle edin .

Ancak bu gereksizdir else . elseanlatırken kullanılır varsayılan-durum . İkinci bir adımda,

bool CanLeaveWithoutUmbrella()
{
    bool result=false

    if(sky.Color == Color.Blue)
    {
        result = true;
    }
    return result;
}

Sonra soru ortaya çıkıyor: Neden geçici bir değişken kullanılıyor? Yeniden düzenlemenin bir sonraki adımı:

bool CanLeaveWithoutUmbrella()
{

    if(sky.Color == Color.Blue)
    {
        return true;
    }
    return false;
}

Yani bu açık ne yaptığını içinde. Hatta bir adım daha ileri gideceğim:

bool CanLeaveWithoutUmbrella()
{

    if(sky.Color == Color.Blue) return true;
    return false;
}

Ya da hafif yürekli :

bool CanLeaveWithoutUmbrella()
{

    if(sky.Color == Color.Blue) { return true; }
    return false;
}

Bunu şöyle okuyabilirsiniz: »CanLeaveWithoutUmbrella bir bool döndürür . Özel bir şey olmazsa yanlış döndürür. «Bu ilk okuma, yukarıdan aşağıya.

Ve sonra koşulu "ayrıştırırsınız" Koşul yerine getirilirse , true değerini döndürür «Koşulları tamamen atlayabilir ve bu işlevin varsayılan -case'de ne yaptığını anlayabilirsiniz. Gözünüz ve zihniniz, sağ taraftaki bölümü okumadan sadece sol taraftaki bazı harfleri gözden geçirmelidir.

Her iki bloktaki kodun doğrudan ilişkili olduğu gerçeğini belirterek, daha doğrudan niyetleri ifade eden izlenim altındayım.

Evet bu doğru. Ancak bu bilgi gereksizdir . Varsayılan bir durum ve if-statement tarafından kapsanan bir "özel durum" vardır .

Karmaşık yapılarla uğraşırken, ifçirkin kardeşini atlayarak veya başka bir stratejiyi seçerdim switch.


+1 fazlalığı kesinlikle sadece karmaşıklıkta değil, karışıklıkta da bir artış gösterir. Ben her zaman tam olarak fazlalık nedeniyle böyle yazılan kodu kontrol zorunda kaldım biliyorum.
dietbuddha

1
Dava ile başladıktan sonra davaları So this is clear in what it does...açıp genişletebilir misiniz? (Önceki davalar da tartışmalı bir konudur). Bunu söylüyorum çünkü soruyu incelemek istediğimiz şey bu. Duruşunuzu söylediniz, diğer bloğu atlayın ve aslında daha fazla açıklama gerektiren duruş (ve bu soruyu sormamı sağlayan). I ask that you ignore the many other ways the function can be written, and changes that can be made to it. (I know most people are itching to write return sky.Color == Color.Blue.)
Sorudan

@AssortedTrailmix Elbette! Tam olarak nelere dikkat etmeliyim? İlk sorunuz “Başka bloklar kod karmaşıklığını artırıyor mu?” Olduğundan ve cevabım: evet. Bu durumda atlanabilir.
Thomas Junk

Ve hayır! Aşağı oyu anlamıyorum.
Thomas Junk

-1

Uzun bir hikayeyi kısaltmak için, bu durumda, elseanahtar kelimeden kurtulmak iyi bir şeydir. Burada tamamen gereksizdir ve kodunuzu nasıl biçimlendirdiğinize bağlı olarak, kodunuza bir ila üç tamamen daha yararsız satır ekleyecektir . ifBlokta neler olduğunu düşünün :

return true;

Bu nedenle, ifblok girilecekse, işlevin geri kalan kısmı tanım gereği yürütülmez. Ancak, girilmezse, başka ififade olmadığından , işlevin geri kalanının tamamı yürütülür. Bir returnifadenin ifblokta olmaması tamamen farklı olurdu , bu durumda bir elsebloğun varlığı veya yokluğu bir etki yaratacaktır, ancak burada bir etkisi olmayacaktır.

Sorunuzda, ifdurumunuzu tersine çevirdikten ve atladıktan elsesonra aşağıdakileri söylediniz:

Birisi, ilk koşuldan hemen sonra ilk koşulu hemen kendi koşuluna bir kısıtlama koymadan farketmeden bir koşula dayalı yeni bir if bloğu ekleyebilir.

O zaman kodu biraz daha yakından okumalıdırlar. Bu sorunları hafifletmek için yüksek düzeyli diller ve açık kod düzenlemesi kullanıyoruz, ancak tamamen yedekli bir elseblok eklemek koda "gürültü" ve "karmaşa" ekliyor ve ifkoşullarımızı da tersine çevirmek veya tersine çevirmek zorunda kalmamalıyız . Farkı söyleyemezlerse, ne yaptıklarını bilmiyorlar. Farkı söyleyebilirlerse, orijinal ifkoşulları her zaman tersine çevirebilirler .

Başka bir bloğun atlanmasına katıldığım bir durumdan bahsetmeyi unuttum ve bir null blok (null check (veya başka korumalar) gibi aşağıdaki tüm kodlar için mantıksal olarak tatmin edilmesi gereken bir kısıtlama uygulamak için kullanılıyorsa ).

Aslında burada olan da budur. ifBloktan dönüyorsunuz , bu nedenle ifdeğerlendirilen koşul false , aşağıdaki tüm kodlar için mantıksal olarak karşılanması gereken bir kısıtlamadır.

Başka blok dahil edilmemenin getirdiği karmaşıklıkta bir artış var mı?

Hayır, kodunuzdaki karmaşıklıkta bir azalma oluşturacak ve bazı süper önemsiz optimizasyonların gerçekleşip gerçekleşmeyeceğine bağlı olarak derlenmiş kodda bir düşüş bile oluşturabilir.


2
"O zaman kodu biraz daha yakından okumalılar." Kodlama stili, programcıların nitpicky ayrıntılarına daha az dikkat etmelerini ve gerçekte yaptıklarına daha fazla dikkat etmelerini sağlar. Tarzınız bu detaylara gereksiz yere dikkat etmenizi sağlıyorsa, bu kötü bir stil. “... tamamen işe yaramaz çizgiler ...” İşe yaramazlar - bir bakışta yapının ne olduğunu görmenizi sağlarlar, bu parça ya da o parça yürütülürse ne olacağı hakkında zaman harcamak zorunda kalmadan.
Michael Shaw

@MichaelShaw Sanırım Aviv Cohn'un cevabı bahsettiğim konuya giriyor.
Panzercrisis

-2

Verdiğiniz özel örnekte, öyle.

  • Bir gözden geçireni, hata olmadığından emin olmak için kodu tekrar okumaya zorlar.
  • Akış grafiğine bir düğüm eklediğinden (gereksiz) siklomatik karmaşıklık ekler.

Bunun daha basit olamazdı düşünüyorum:

bool CanLeaveWithoutUmbrella()
{
    return (sky.Color == Color.Blue);
}

6
Bu çok basitleştirilmiş örneğinif ifadeyi kaldırmak için yeniden yazılabileceği gerçeğine özellikle değiniyorum . Aslında, tam olarak kullandığınız kodu kullanarak daha fazla sadeleştirmeyi önermiyorum. Ayrıca, elseblok tarafından siklomatik karmaşıklık artmaz .
Selali Adobor

-4

Ben her zaman niyetimi olabildiğince açık olacak şekilde kodumu yazmaya çalışın. Örneğinizde bir bağlam eksik, bu yüzden biraz değiştireceğim:

class Sky {
    Sky(Colour c)
    {
        this.color = c;
    }
    bool CanLeaveWithoutUmbrella()
    {
        if(this.color == Color.Blue)
        {
            return true;
        }
        else
        {
            return false;
        }
    }
}

Amacımız gibi görünüyor , Gökyüzü Mavi olduğunda şemsiye olmadan ayrılabileceğimiz . Ancak bu basit niyet bir kod denizinde kaybolur. Anlaşmayı kolaylaştırabileceğimiz birkaç yol var.

İlk olarak, elseşube hakkında sorunuz var . Ben her iki şekilde de umursamıyorum, ama dışarıda bırakma eğilimindedir else. Açık olma iddiasını anlıyorum, ama benim düşüncem, ififadelerin 'isteğe bağlı' dalları, örneğin, dalları sarması gerektiğidir return true. Ben demem return falsebizim varsayılan olarak davranıyor çünkü, 'isteğe bağlı' dalı. Her iki durumda da, bunu çok küçük bir sorun olarak görüyorum ve aşağıdakilerden çok daha az önemli:

class Sky {
    Sky(Colour c)
    {
        this.color = c;
    }
    bool CanLeaveWithoutUmbrella()
    {
        if(this.color == Color.Blue)
        {
            return true;
        }
        return false;
    }
}

Bir çok daha önemli bir konu da dalları çok fazla yapıyor olmasıdır! Şubeler, her şey gibi, 'olabildiğince basit, ama artık değil' olmalıdır. Bu durumda if, aralarında gerçekten dallamanız gereken tek şey ifadeler (değerler) olduğunda kod blokları (ifadeler koleksiyonu) arasında dallar içeren bir ifade kullandınız . Bu açıktır, çünkü a) kod bloklarınız yalnızca tekli ifadeler içerir ve b) aynı ifadedir ( ). Üçlü operatörü , şubeyi yalnızca farklı olan bölüme daraltmak için kullanabiliriz :return?:

class Sky {
    Sky(Colour c)
    {
        this.color = c;
    }
    bool CanLeaveWithoutUmbrella()
    {
        return (this.color == Color.Blue)
            ? true
            : false;
    }
}

Şimdi, sonucumuzun özdeş olduğu açık bir fazlalığa ulaşıyoruz this.color == Color.Blue. Sorunuzun bunu görmezden gelmemizi istediğini biliyorum, ancak bunun çok birinci dereceden, prosedürel bir düşünme yolu olduğunu belirtmenin gerçekten önemli olduğunu düşünüyorum: giriş değerlerini yıkıyorsunuz ve bazı çıkış değerleri oluşturuyorsunuz. Bu iyi, ancak mümkünse , girdi ve çıktı arasındaki ilişkiler veya dönüşümler açısından düşünmek çok daha güçlü . Bu durumda ilişki açıkça aynıdır, ancak çoğu zaman böyle basit bir ilişkiyi gizleyen kıvrımlı prosedür kodu görüyorum. Devam edelim ve bu basitleştirmeyi yapalım:

class Sky {
    Sky(Colour c)
    {
        this.color = c;
    }
    bool CanLeaveWithoutUmbrella()
    {
        return (this.color == Color.Blue);
    }
}

Ben işaret ediyorum sonraki şey API çift negatif içerdiğini şudur: için mümkün CanLeaveWithoutUmbrellaolduğu false. Bu, elbette, NeedUmbrellavarlığı basitleştirir true, bu yüzden şunu yapalım:

class Sky {
    Sky(Colour c)
    {
        this.color = c;
    }
    bool NeedUmbrella()
    {
        return (this.color != Color.Blue);
    }
}

Şimdi kodlama stilinizi düşünmeye başlayabiliriz. Görünüşe göre Nesneye Dayalı bir dil kullanıyorsunuz, ancak ifkod blokları arasında dal oluşturmak için ifadeler kullanarak , işlem kodu yazdınız.

Nesneye Yönelik kodda, tüm kod blokları yöntemdir ve tüm dallanma dinamik gönderme yoluyla yapılır , örn. sınıflar veya prototipler kullanarak. Bunun işleri daha basit hale getirip getirmediği tartışmalıdır, ancak kodunuzu dilin geri kalanıyla daha tutarlı hale getirmelidir:

class Sky {
    bool NeedUmbrella()
    {
        return true;
    }
}

class BlueSky extends Sky {
    bool NeedUmbrella()
    {
        return false;
    }
}

Üçlü işleçleri ifadeler arasında dallamak için kullanmanın işlevsel programlamada yaygın olduğunu unutmayın .


Cevabın ilk paragrafı soruyu cevaplama yolunda gibi görünüyor, ancak hemen bu çok basit örnek için göz ardı ettiğim açıkça konuya yöneliyor . Sorusuna Gönderen: I ask that you ignore the many other ways the function can be written, and changes that can be made to it. (I know most people are itching to write return sky.Color == Color.Blue.). Aslında bahsettiğim tam kod satırını kullanıyorsunuz. Ayrıca, sorunun bu kısmı konu dışı olsa da, çıkarımda çok ilerlediğinizi söyleyebilirim. Sen ettik kökten kodu ne değişti.
Selali Adobor

@AssortedTrailmix Bu tamamen bir stil meselesidir. Stili önemsemek mantıklı ve onu görmezden gelmek mantıklı (sadece sonuçlara odaklanmak). Ben bu konuda bakım mantıklı sanmıyorum return false;vs else { return false; }iken değil , bir OO dilde prosedürel kod yazıyorsanız, radikal değişim gereklidir vb şube polarite, dinamik dağıtım ternaries, yaklaşık sevecen;)
Warbo

Genel olarak böyle bir şey söyleyebilirsiniz, ancak iyi tanımlanmış parametrelerle bir soruyu cevaplarken geçerli değildir (özellikle bu parametrelere saygı duymadan tüm soruyu "soyutlayabilirsiniz"). Son cümlenin sadece yanlış olduğunu da söyleyebilirim. OOP, "prosedürel obliterasyon" ile değil, "prosedürel soyutlama" ile ilgilidir. Tek bir astardan sonsuz sayıda sınıfa gittiğiniz gerçeğinin (her renk için bir tane) nedenini gösterdiğini söyleyebilirim . Buna ek olarak, bir dinamik if/elseifadenin bir deyimle ne yapması gerektiğini ve şube polaritesinin ne olduğunu merak ediyorum .
Selali Adobor

OO çözümünün daha iyi olduğunu söylemedim (aslında fonksiyonel programlamayı tercih ederim), sadece dil ile daha tutarlı olduğunu söylemiştim. "Polarite" ile kastım "doğru", hangisi "yanlış" ("NeedUmbrella" ile değiştirdim). OO tasarımında, tüm kontrol akışı dinamik gönderimle belirlenir. Örneğin, Smalltalk başka hiçbir şeye izin vermez en.wikipedia.org/wiki/Smalltalk#Control_structures (ayrıca bkz. C2.com/cgi/wiki?HeInventedTheTerm )
Warbo

2
Son paragrafa (OO hakkında) ulaşana kadar bunu iptal etmiş olurdum, bunun yerine bir alt oy aldı! Tam olarak spagetti kadar okunamayan mantı kodu üreten OO yapılarının düşüncesizce aşırı kullanımı .
zwol
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.