Switch Tablolarını Yeniden Yönlendirmek ve Switch Statements için gerçek bir kullanım var mı?


28

Bu makaleyi okuyordum ve merak ediyordum, tüm anahtar ifadelerimden hiçbirini bir Sözlük veya Fabrika ile değiştirerek kurtuluyor muyuz, böylece projelerimde hiçbir anahtar ifadesi kalmıyor.

Bir şey pek eklemedi.

Sorun şudur: switch ifadelerinin herhangi bir gerçek kullanımı var mıdır yoksa devam edelim ve bunları bir sözlük veya fabrika yöntemiyle değiştirir miyiz? (Bir fabrika yöntemi kullanıldığında, elbette, nesneler oluşturmak için minimum anahtar ifadeleri kullanılacaktır) fabrikayı kullanmak ... ama bununla ilgili).


10
Bir fabrika uyguladığınızı varsayarsak, ne tür bir nesne oluşturacağınıza nasıl karar vereceksiniz?
CodeART


@CodeWorks: Elbette hangi somut uygulamanın kullanılacağına karar verecek bir koşulum olacak.
Kanini

@CodeWorks: Açıkçası, sanal bir kurucu ile. (Eğer bir fabrika modelini bu şekilde uygulayamazsanız, daha iyi bir dile ihtiyacınız var.)
Mason Wheeler

Yanıtlar:


44

Hem switchifadeler hem de polimorfizm onların kullanımına sahiptir. Üçüncü bir seçeneğin de mevcut olduğuna dikkat edin (işlev işaretçiler / lambdas ve üst düzey işlevleri destekleyen dillerde): söz konusu tanımlayıcıları işleyici işlevleriyle eşleştirme. Bu, örneğin OO dili olmayan C, Java * da * olan C # ve (henüz) Java'da OO * olarak da bulunur.

Bazı prosedürel dillerde (polimorfizme ve üst düzey fonksiyonlara sahip değil) switch/ if-elseifadeler bir problem sınıfını çözmenin tek yoluydu. Bu düşünce tarzına alışmış olan birçok geliştirici, switchpolimorfizmin genellikle daha iyi bir çözüm olduğu OO dillerinde bile kullanılmaya devam etti . Bu nedenle switchpolimorfizm lehinde / refactor ifadelerinden kaçınmak genellikle tavsiye edilir .

Her halükarda, en iyi çözüm her zaman büyük / küçük harfe bağlıdır. Soru şudur: Uzun vadede hangi seçenek size daha temiz, daha özlü ve daha fazla bakım yapılabilir kod veriyor?

Switch deyimleri genellikle düzinelerce büyüyebilir, düzinelerce davaya bakılarak bakımlarını zorlaştırabilir. Onları tek bir işlevde tutmanız gerektiğinden, bu işlev çok büyük olabilir. Bu durumda, harita tabanlı ve / veya polimorfik bir çözüme doğru yeniden yönlendirme yapmayı düşünmelisiniz.

Aynı durum switchbirden fazla yerde açılmaya başlarsa, polimorfizm muhtemelen tüm bu durumları birleştirmek ve kodu basitleştirmek için en iyi seçenektir. Özellikle gelecekte daha fazla vaka eklenmesi bekleniyorsa; Her seferinde güncelleme yapmanız gereken yerler arttıkça, hatalar için olasılıklar artar. Bununla birlikte, çoğu zaman bireysel vaka işleyicileri çok basittir veya çok fazla kişi vardır ya da birbirleriyle ilişkilidirler, onları tam bir polimorfik sınıf hiyerarşisine yeniden yansıtmak, fazladan yazılır veya çoğaltılmış bir kod ve / veya karışıklık ile sonuçlanır. sınıf hiyerarşisini korumak zor. Bu durumda, bunun yerine fonksiyon / lambdas kullanmak daha kolay olabilir (eğer diliniz izin veriyorsa).

Ancak, switchtek bir yere sahipseniz , sadece birkaç vaka basit bir şey yapıyorsa , olduğu gibi bırakmanız en iyi çözüm olabilir.

* Burada "OO" terimini gevşek kullanıyorum; Neyin “gerçek” veya “saf” OO ile ilgili kavramsal tartışmalarla ilgilenmiyorum.


4
+1. Ayrıca, bu öneriler, “ geçiş için polimorfizmi tercih etme ” ifadesiyle ifade edilme eğilimindedir ve bu, bu cevabı çok iyi karşılayan bir kelime seçimidir. Sorumlu bir kodlayıcının diğer seçimi yapabileceği durumlar olduğunu kabul eder.
Carl Manaster

1
Ve kodunuzda bir gazillion olsa bile, anahtar yaklaşımını istediğiniz zamanlar vardır. 3B labirent üreten aklımda bir kod parçası var. Dizideki bir baytlık hücreler sınıflarla değiştirildiyse, bellek kullanımı artacaktır.
Loren Pechtel

14

Burası dinozor olmaya döndüğüm yer ...

Switch deyimleri kendi başlarına hiç de fena değil, söz konusu olan onlardan kullanımı.

En açık olanı, kötü olan kodunuzla tekrar tekrar tekrar tekrar tekrarlanan "aynı" anahtar ifadesidir (orada yapıldı, bunu yaptım, tekrar etmemek için her türlü çabayı gösterecekti) - polimorfizm kullanarak. Genellikle iç içe geçmiş davalar için de oldukça korkunç bir şey var (mutlak bir canavara sahiptim - şu an "daha iyi" dışında başka bir şeyle nasıl başa çıkacağımdan tam olarak emin değilim).

Anahtar olarak sözlük Daha zorlu buluyorum - temelde evet, anahtarınız vakaların% 100'ünü kapsıyorsa, ancak varsayılan veya aksiyon davalarına sahip olmak istemediğiniz durumlarda biraz daha ilginçleşmeye başlar.

Tekrarlamadan kaçınma ve nesne grafiklerimizi doğru yerlerde oluşturduğumuzdan emin olma meselesi olduğunu düşünüyorum.

Ama aynı zamanda anlama (sürdürülebilirlik) argümanı da var ve bu her iki yolu da kesiyor - her şeyin nasıl çalıştığını (uygulamanın modelini ve uygulandığı uygulamayı) kolaylaştığını anladıktan sonra… Yeni bir şey eklemek zorundasınız, sonra neyi eklemeniz / değiştirmeniz gerektiğine karar vermek için her yere atlamak zorundasınız.

Gelişme ortamlarımız kitlesel olarak yetenekli olduğu için, kağıda basılmış (sanki) kodları anlayabilmenin istendiğini düşünüyorum - kodu parmağınızla takip edebilir misiniz? Aslında hayır olarak kabul ediyorum, bugün pek çok iyi uygulama ile yapamazsınız ve iyi nedenlerle ama bu kodla hızlanmaya başlamanın daha zor (ya da belki sadece yaşlıyım ...) anlamına gelir


4
İdeal olarak kodun yazılması gerektiğini söyleyen bir öğretmenim vardı, "programlama hakkında hiçbir şey bilmeyen biri (belki de annen gibi) anlayabilecekti." Ne yazık ki bu ideal, ama belki de annelerimizi yine de kod incelemelerine dahil etmeliyiz!
Michael K,

1 "Bir şeyi eklemek zorunda tek bir kod çizgisine gelirse ancak yeni o zaman / değişikliğini eklemek için gerekenleri çalışmak için biryere atlamak zorunda" için
quickly_now

8

Alt tür polimorfizmine karşı anahtar ifadeleri eski bir sorundur ve Sıkça Soruşturma Sorunu ile ilgili tartışmalarda ÇP topluluğunda sıklıkla anılır .

Temel olarak, tiplerimiz (sınıflarımız) ve fonksiyonlarımız (metodlarımız) var. Maddeleri nasıl kodlayacağız, böylece yeni türler veya yeni yöntemler eklemek daha kolaydır?

Eğer OO tarzında programlıyorsanız, yeni bir yöntem eklemek zordur (çünkü mevcut tüm sınıfları yeniden düzenlemek anlamına gelir), ancak eskisi gibi yöntemleri kullanan yeni sınıflar eklemek çok kolaydır.

Öte yandan, bir switch ifadesi (veya OO eşdeğeri, Gözlemci Kalıbı) kullanırsanız, yeni işlevler eklemek çok kolaydır, ancak yeni vakalar / sınıflar eklemek zordur.

Her iki yönde de iyi bir genişletilebilirliğe sahip olmak kolay değildir, bu nedenle kodunuzu yazarken, hangi yöne uzatma olasılığınıza bağlı olarak polimorfizm kullanıp kullanmamaya karar verin.


4
Projelerimde hiçbir anahtar ifadesi bulunmayacak şekilde tüm anahtar ifadelerimizi bir Sözlük veya Fabrika ile değiştirerek kurtuluyor muyuz?

Hayır. Bu mutlaklıklar nadiren iyi bir fikirdir.

Birçok yerde, bir sözlük / arama / fabrika / polimorfik gönderim, bir anahtar ifadesinden daha iyi bir tasarım sağlayacaktır, ancak yine de sözlüğü doldurmanız gerekir. Bazı durumlarda, bu gerçekten neler olup bittiğini gizleyecektir ve switch anahtarını satır içi satırına sokmak daha okunaklı ve bakım gerektirebilir.


Ve gerçekten, fabrikayı, sözlüğü ve aramayı kaldırırsanız, temelde bir anahtar deyimi olarak ortaya çıkacaktı: eğer array [hash (search)], sonra array [hash (search)] 'i çağırın. Her ne kadar derlenmiş anahtarlar çalışma zamanının genişletilebilir olmasına rağmen.
Zan Lynx,

@ZanLynx, tam tersi doğrudur, en azından C # ile. Önemsiz olmayan bir anahtar ifadesi için üretilen IL'ye bakarsanız, derleyicinin onu bir sözlüğe dönüştürdüğünü görürsünüz.
David Arno

@DavidArno: "tam tersi"? Okuduğum şekilde, aynı şeyi söyledik. Nasıl tersi olabilir?
Zan Lynx

2

Bunun dil ile nasıl uyumlu olduğunu görünce, kod çözme kodu switchifadelerle en iyi sonucu verir :

switch(something) {
   case 1:
      foo();
   case 2:
      bar();
      baz();
      break;

   case 3:
      bang();
   default:
      bizzap();
      break;
}

Çok garip bir varsayılan dava ifile eşdeğer . Ve orada ne kadar sıkıntı olursa, durum listesinin o kadar uzun süreceğini unutmayın:

if (1 == something) {
   foo();
}
if (1 == something || 2 == something) {
   bar();
   baz();
}
if (3 == something) {
   bang();
}
if (1 != something && 2 != something) {
   bizzap();
}

(Bununla birlikte, diğer cevapların bazılarının söylediklerine göre, sorunun amacını kaçırmışım gibi hissediyorum ...)


Düşme ifadelerinin a switchile aynı düzeyde kullanılmasını düşünürdüm goto. Gerçekleştirilecek algoritma, yapısal programlama yapılarına uygun kontrol akışları gerektiriyorsa, bu tür yapılar kullanılmalıdır, ancak algoritma bu tür yapılara uymuyorsa, kullanım, gotodiğer kontrol yapılarına uymak için bayrak veya diğer kontrol mantığını eklemeye çalışmaktan daha iyi olabilir .
supercat

1

Durum farklılaşması olarak ifadeleri değiştirmek gerçek bir kullanım alanıdır. İşlevsel programlama dilleri, girişe bağlı olarak işlevleri farklı şekilde tanımlamanıza olanak tanıyan desen eşleştirme adı verilen bir şey kullanır. Bununla birlikte, nesne yönelimli dillerde, polimorfizm kullanılarak aynı amaca daha zarif bir şekilde ulaşılabilir. Siz sadece metodu çağırırsınız ve nesnenin gerçek tipine bağlı olarak, metodun ilgili uygulaması gerçekleştirilir. Bu fikrin arkasındaki neden, anahtar ifadelerinin kod kokusu olmasıdır. Ancak, OO dillerinde bile, onları soyut fabrika modelini uygulamak için yararlı bulabilirsiniz.

tl; dr - onlar faydalıdır, ancak genellikle daha iyisini yapabilirsiniz.


2
Orada bir önyargı kokusu alıyorum - neden polimorfizm örüntü eşlemesinden daha şık Ve polimorfizmin FP'de var olmadığını düşündüren nedir?
tdammers

@tdammers Her şeyden önce FP'da polimorfizmin bulunmadığını ima etmek istemedim. Haskell geçici ve parametrik polimorfizmi destekler. Desen eşleştirme cebirsel veri türü için anlamlıdır. Ancak harici modüller için bu, kurucuların açığa çıkmasını gerektirir. Açıkçası bu, soyut bir veri tipinin (cebirsel veri tipleriyle gerçekleştirilmiş) enkapsülasyonunu keser. Bu nedenle polimorfizmin daha zarif (ve FP'de mümkün) olduğunu hissediyorum.
Fular

Polimorfizmi, sınıflar ve örnekler aracılığıyla unutuyorsunuz.
tdammers

İfade Problemini hiç duydunuz mu? Eğer düşünmeyi keserseniz, OO ve FP farklı durumlarda daha iyidir.
hugomg

@tdammers Özel polimorfizmden bahsettiğimde ne tür polimorfizmden bahsettiğimi düşünüyorsunuz? Geçici polimorfizm Haskell'de tip sınıfları ile gerçekleştirilir. Unuttuğumu nasıl söylersin? Sadece doğru değil.
eşarp
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.