Kontrol akışının onu gereksiz kıldığı durumlarda “başka” kullanılmalı mıdır?


18

Bazen aşağıdaki örneğe benzer kod üzerine rastlamak (bu fonksiyon tam olarak bu sorunun kapsamı dışında ne yapar):

function doSomething(value) {
  if (check1(value)) {
    return -1;
  }
  else if (check2(value)) {
    return value;
  }
  else {
    return false;
  }
}

Gördüğünüz gibi if, else ifve elseifadeleri ifadeyle birlikte kullanılır return. Bu rahat bir gözlemci için oldukça sezgisel görünüyor, ama ben else-s bırakmak ve böyle kodu basitleştirmek için (bir yazılım geliştirici açısından) daha zarif olacağını düşünüyorum :

function doSomething(value) {
  if (check1(value)) {
    return -1;
  }
  if (check2(value)) {
    return value;
  }
  return false;
}

Bir returnifadeyi izleyen her şey (aynı kapsamda) hiçbir zaman yürütülmeyeceğinden bu mantıklıdır; yukarıdaki kod anlamsal olarak ilk örneğe eşittir.

Yukarıdakilerden hangisi iyi kodlama uygulamalarına daha çok uyuyor? Her iki yöntemin de kod okunabilirliği açısından herhangi bir dezavantajı var mı?

Düzenleme: Bu soru referans olarak sağlanan yinelenen bir öneri yapılmıştır . Diğer soruda gösterildiği gibi yinelenen ifadelerden kaçınmayı istemediğim için sorumun farklı bir konuya değindiğine inanıyorum. Her iki soru da biraz farklı şekillerde de olsa tekrarları azaltmaya çalışır.


14
Daha elseaz sorun, daha büyük sorun, iki veri türünü tek bir işlevden geri döndürmenizdir, bu da işlevin API'sını tahmin edilemez hale getirir.
Andy

3
E_CLEARLY_NOTADUPE
kojiro

3
@DavidPacker: En az iki; üç olabilir. -1bir sayıdır, falsebir boole'dir ve valueburada belirtilmez, böylece herhangi bir nesne türü olabilir.
Yay295

1
@ Yay295 valueAslında tamsayı olmasını umuyordum . Eğer bir şey olabilirse, o zaman daha da kötüdür.
Andy

@DavidPacker Bu, özellikle iyi uygulamalar hakkında bir soru yöneltildiğinde çok önemli bir noktadır. Size ve Yay295'e katılıyorum, ancak kod örnekleri, ilişkisiz bir kodlama tekniğini göstermek için bir örnek olarak hizmet ediyor. Yine de, bunun önemli bir konu olduğunu ve gerçek kodda göz ardı edilmemesi gerektiğini unutmayın.
gergedan

Yanıtlar:


23

Onsuz olanı seviyorum elseve işte neden:

function doSomething(value) {
  //if (check1(value)) {
  //  return -1;
  //}
  if (check2(value)) {
    return value;
  }
  return false;
}

Çünkü bunu yapmak gerekmediği hiçbir şeyi kırmadı.

Tüm formlarında nefret bağımlılığı (bir işlevi adlandırmak dahil check2()). İzole edilebilecek her şeyi izole edin. Bazen ihtiyacınız olur elseama bunu burada görmüyorum.


Bunu genel olarak burada da belirtildiği için tercih ederim. Ancak, genellikle kodu okurken, kod bloğundan sonra tek amaçlanan yürütme deyimdeki koşul yanlışsa , netleştirmek için her ifbloğun yakın bir yorum yerleştirin . Böyle bir şey olmadan, özellikle blok içindeki kod daha karmaşık hale gelirse, koşulun doğru olduğu durumlarda niyetin hiçbir zaman bloktan geçmemesi gereken kodu koruduğu herkes için net olmayabilir . } //elseififififif
Makyen

@Makyen iyi bir noktaya değindin. Biri görmezden gelmeye çalışıyordum. Ayrıca if, kodun bu bölümünün yapıldığını ve yapının bittiğini açıklığa kavuşturmak için bir şey yapılması gerektiğine inanıyorum . Bunu yapmak için burada yapmadığım şeyi yapıyorum (çünkü OP'nin ana noktasından başka değişiklikler yaparak dikkatimi dağıtmak istemedim). Tüm bunları, dikkat dağıtıcı olmadan elde edebileceğim en basit şeyi yapıyorum. Boş bir satır ekliyorum.
candied_orange

27

Kodun anlambilimine bağlı olduğunu düşünüyorum. Üç vakanız birbirine bağımlıysa, açıkça belirtin. Bu, kodun okunabilirliğini artırır ve herkes için anlaşılmasını kolaylaştırır. Misal:

if (x < 0) {
    return false;
} else if (x > 0) {
    return true;
} else {
    throw new IllegalArgumentException();
}

Burada xher üç durumun değerine açıkça bağlısınız . Sonuncuyu atlarsanız else, bu daha az açık olacaktır.

Davalarınız doğrudan birbirine bağlı değilse, atlayın:

if (x < 0) {
    return false;
}
if (y < 0) {
    return true;
}
return false;

Bunu bağlamsız basit bir örnekle göstermek zor, ama umarım benim fikrimi anlarsın.


6

Ben ikinci seçeneği (ayrı tercih ifshayır ile else iferken ve return) ANCAK olmasıdır sürece kod blokları kısa oldukları gibi .

Kod blokları uzunsa kullanmak daha iyidir else if, çünkü aksi takdirde kodun sahip olduğu birkaç çıkış noktasını net bir şekilde anlayamazsınız.

Örneğin:

function doSomething(value) {
  if (check1(value)) {
    // ...
    // imagine 200 lines of code
    // ...
    return -1;
  }
  if (check2(value)) {
    // ...
    // imagine 150 lines of code
    // ...
    return value;
  }
  return false;
}

Bu durumda, daha iyi kullanmak else if, dönüş kodunu bir değişkende saklamak ve sonunda sadece bir dönüş cümlesine sahip olmak.

function doSomething(value) {
  retVal=0;
  if (check1(value)) {
    // ...
    // imagine 200 lines of code
    // ...
    retVal=-1;
  } else if (check2(value)) {
    // ...
    // imagne 150 lines of code
    retVal=value;
  }
  return retVal;
}

Ancak, işlevlerin kısa olması için çaba göstermesi gerektiği gibi, kısa tutun ve ilk kod snippet'inizdeki gibi erken çıkın.


1
Öncülünüze katılıyorum, ancak kodun nasıl olması gerektiğini tartıştığımız sürece, sadece kod bloklarının kısa olması gerektiği konusunda hemfikir miyiz? Eğer seçmek zorunda olsaydım, başka bir kullanmak için fonksiyonlara kırık değil uzun bir kod bloğu olması daha kötü olduğunu düşünüyorum.
kojiro

1
Meraklı bir tartışma. return3 satır içindedir, ifbu yüzden else if200 satır koddan sonra bile farklı değildir . Tek dönüş tarzı burada tanıtmak istisnalarla birlikte hataları rapor etmez c ve diğer dillerde bir gelenektir. Mesele, kaynakları temizlemek için tek bir yer yaratmaktı. İstisna dilleri bunun için bir finallyblok kullanır . Ben de bu hata ayıklayıcı kıvırcık küme ayracı kapanış fonksiyonları koymak izin olmaz alışkanlık koymak için bir yer oluşturur varsayalım.
candied_orange

4
Görevi hiç sevmiyorum retVal. Bir işlevden güvenli bir şekilde çıkabiliyorsanız, işlevden tek bir çıkış değişkenine döndürülecek güvenli değeri atamadan hemen yapın. Tek bir dönüş noktasını gerçekten uzun bir fonksiyonda kullandığınızda, genellikle diğer programcılara güvenmiyorum ve sonuçta dönüş değerinin diğer modifikasyonları için fonksiyonun geri kalanına bakıyorum. Hızlı başarısız olma ve erken dönme, diğerleri arasında, yaşadığım iki kural.
Andy

2
Bence uzun bloklar için daha da kötü. Dış bağlam ne olursa olsun işlevlerden olabildiğince erken çıkmaya çalışıyorum.
Andy

2
DavidPacker ile birlikteyim. Tek dönüş tarzı, bizi tüm atama noktalarını ve atama noktalarından sonraki kodu incelemeye zorlar. Erken dönüş tarzının çıkış noktalarını incelemek uzun ya da kısa benim için tercih edilir. Dil nihayet bir bloğa izin verdiği sürece.
candied_orange

4

Her ikisini de farklı koşullarda kullanıyorum. Doğrulama kontrolünde, diğerini atlıyorum. Bir kontrol akışında diğerini kullanıyorum.

bool doWork(string name) {
  if(name.empty()) {
    return false;
  }

  //...do work
  return true;
}

vs

bool doWork(int value) {
  if(value % 2 == 0) {
    doWorkWithEvenNumber(value);
  }
  else {
    doWorkWithOddNumber(value);
  }
}

İlk durumda, daha önce tüm önkoşulları kontrol ediyor, bunları ortadan kaldırıyor ve daha sonra çalıştırmak istediğiniz gerçek koda ilerliyormuşsunuz gibi daha fazla bilgi geliyor. Bu nedenle, gerçekten çalıştırmak istediğiniz sulu kod doğrudan işlevin kapsamına aittir; işlevin gerçekte ne hakkında olduğunu.
İkinci durum, her iki yolun da çalışacak geçerli kod olduğu gibi, bazı koşullara dayalı olarak işlevle ilgili olanla aynıdır. Bu itibarla, birbirine benzer kapsam seviyelerine aittirler.


0

Gerçekten önemli gördüğüm tek durum böyle kod:

List<?> toList() {
    if (left != null && right != null) {
        Arrays.asList(merge(left, right));
    }
    if (left != null) {
        return Arrays.asList(left);
    }
    if (right != null) {
        return Arrays.asList(right);
    }
    return Arrays.asList();
}

Burada yanlış bir şeyler var. Sorun şu ki, returneklenip eklenmeyeceği belli değil Arrays.asList. İlgili yöntemlerin daha ayrıntılı incelenmesi olmadan bunu düzeltemezsiniz. Her zaman tam kapsamlı if-else blokları kullanarak bu belirsizliği önleyebilirsiniz. Bu:

List<?> toList() {
    if (left != null && right != null) {
        Arrays.asList(merge(left, right));
    } else if (left != null) {
        return Arrays.asList(left);
    } else if (right != null) {
        return Arrays.asList(right);
    } else {
        return Arrays.asList();
    }
}

önce açık dönüş eklemezseniz derlemez (statik olarak kontrol edilen dillerde) if.

Bazı diller ilk stile bile izin vermez. Sadece kesinlikle zorunlu bağlamda veya uzun yöntemlerde ön koşullar için kullanmaya çalışıyorum:

List<?> toList() {
    if (left == null || right == null) {
        throw new IllegalStateException()
    }
    // ...
    // long method
    // ...
}

-2

Eğer kodu ve kötü uygulamayı takip etmeye çalışıyorsanız, böyle fonksiyondan üç çıkış olması gerçekten kafa karıştırıcıdır.

İşlev için tek bir çıkış noktanız varsa, elses gereklidir.

var result;
if(check1(value)
{
    result = -1;
}
else if(check2(value))
{
    result = value;
}
else 
{
    result = 0;
}
return result;

Aslında daha da ileri gidelim.

var result = 0;
var c1 = check1(value);
var c2 = check2(value);

if(c1)
{
    result = -1;
}
else if(c2)
{
    result = value;
}

return result;

Giriş doğrulamasında tek bir erken getiri için tartışabileceğiniz kadar adil. Sadece bir if içinde mantığı tüm toplu sarma kaçının.


3
Bu stil, açık kaynak yönetimine sahip dillerden gelir. Tahsis edilen kaynakları boşaltmak için tek noktaya ihtiyaç vardı. Otomatik kaynak yönetimine sahip dillerde tek dönüş noktası o kadar önemli değildir. Değişkenlerin sayısını ve kapsamını azaltmaya odaklanmalısınız.
Banthar

a: soruda herhangi bir dil belirtilmemiş. b: Sanırım bu konuda yanlışsın. tek dönüş için birçok iyi neden var. karmaşıklığı azaltır ve okunabilirliği artırır
Ewan

1
Bazen karmaşıklığı azaltır, bazen arttırır. Bkz wiki.c2.com/?ArrowAntiPattern
Robert Johnson

Hayır, her zaman siklomatik karmaşıklığı azalttığını düşünüyorum, ikinci örneğime bakın. check2 her zaman çalışır
Ewan

erken dönüşün olması, bazı kodları koşullu hale getirerek kodu karmaşıklaştıran bir optimizasyondur
Ewan

-3

Gereksiz ifadeyi atlamayı tercih ederim. Ne zaman onu görmek (kod inceleme veya yeniden düzenleme) yazar kontrol akışını anlamak ve kodda bir hata olabilir merak ediyorum.

Yazar, else ifadesinin gerekli olduğuna inanıyorsa ve bu nedenle, iade ifadesinin kontrol akışı sonuçlarını anlamıyorsa, kesinlikle böyle bir anlayış eksikliği, bu işlevde ve genel olarak büyük bir hata kaynağıdır.


3
Seninle aynı fikirdeyken bu bir fikir anketi değil. Lütfen taleplerinizi yedekleyin, yoksa seçmenler size nazik davranmazlar.
candied_orange
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.