Bazı değerleri dize olarak saklamak kötü bir uygulama mudur?


19

Bu çok belirsiz bir başlık ama bunu söylemenin daha iyi bir yolunu düşünemedim. Ancak, bir örnek olarak, bir oyundaki bir karakterin hareket ettiği yönü düşünün. Bir string kullanmak ve sonra gibi şeyler yapmak biraz yanlış geliyor if(character.direction == "left"). Bana öyle geliyor ki, yanlışlıkla kullanmak Leftya lda bunun yerine herhangi bir şey gibi aptalca hatalara çok fazla yer bırakıyor left. Şüphelerim doğru mu? Eğer öyleyse, böyle bir şeye ulaşmanın tercih edilen yolu nedir?


10
yani diliniz bunları destekliyorsa, numaralandırmaların yanı sıra?
hoffmale



Bazı diller dize dışındaki değerleri depolayamaz, ör bash.
mouviciel

neden bilmiyorum ama C "tanımlamak" hatırladım gibi şeyler yapabilirsiniz: #define false true
linuxunil

Yanıtlar:


28

Kullandığınız dil numaralandırma kullanımını destekliyorsa, bunları kullanırdım. Belirli bir tür için kullanılabilir seçeneklerin sayısını sınırlamanızı sağlar. örneğin Java'da:

public enum Direction {
    LEFT,
    RIGHT,
    UP,
    DOWN
}

2
Bu cevap OP sorununun anlaşılmasına katkıda bulunmaz; Burada hiçbir gerekçe görmüyorum, sadece enumjava gibi klaslı dillerle sınırlı bir görüş var . Birçok dilde (örn. VBA) vardır enum, ancak gelecekteki aynı provadan yoksun olduğu için en iyi seçenek olmayabilir. enumTek başına neden eksik, çoğu zaman kırılgan ve dile özgü bir çözüm olduğunu tartışmak için cevabımı görün .
16'da sqykly

12

Kodda değişmez dizeler (veya sihirli sayılar) kullanmak korkunç bir uygulamadır.

Numaralandırmalar iyidir veya en azından sabitleri kullanır (tabii ki numaralandırmalar bir veya daha fazla ilgili sabit için yalnızca bir sarıcı tipidir).

const string LEFT = "left"
if (someThing == LEFT) { doStuff(); }

Bu basit anahtarın çok fazla avantajı var, onları nerede açıklamaya başlayacağımı bile bilmiyordum (en azından biraz kahve olmadan). Sihirli sayılar üzerine okuyun, aynı kavramdır, sadece dize değeri yerine bir sayı değerine uygulanır.

İşte hızlı bir ref, eminim yüzlerce kişi daha var: /programming/47882/what-is-a-magic-number-and-why-is-it-bad


1
Bu yaklaşımla ilgili sorun - derleme dizesi LEFT = "letf" gibi yazım hataları almak ise, derleme zamanında yakalanan numaralandırmalar ile çalışıyorsanız.
Pieter B

@PieterB - OPs sorusunun yeterince geniş olduğunu ve "sol" örneğinin sadece keyfi bir örnek olduğunu düşündüm - burada tüm vakalar bir enum ile eşleşmeyecekti. Özellikle bir dizi yön için bir enum'un en iyi seçim olduğunu kabul ediyorum, ancak cevabım "bunu bir değişmeze koyarsanız, en azından sabit hale getirin" (genel olarak, bir tür sabit olmak)
jleach

3
Ben adı "s" ile başlayan o gün olarak hafta sonu günleri atanan bir uygulama ile çalışmaktan zevk aldım. Onlar çok uluslararası onlar uygulama sadece Fransa sadece bir günlük bir hafta sonu vardı "gerçeği" hakkında şaşırdılar.
Pieter B

4
Buna mikrooptimizasyon deyin, ancak bazı diller bunu bir değer karşılaştırması olarak yorumlayabilir ve dizedeki her karakteri kontrol etmek için çok zaman harcayabilir. Asker gibi yapar ve "sol" sabit kodlu dize ile karşılaştırırsanız daha da muhtemeldir. Sabit değerin bir dize olmasına gerek kalmazsa (yani, yazdırmazsanız), bunun yerine bir const int kullanmak daha iyi olur.
Devsman

4

Kısa cevap: Evet, dizeler, bir dizi metin karakterini depolamak ve bunlara erişmek dışında herhangi bir görev için ideal değildir ve bir soyutlamanın temel bitleri dizeler olsa bile, bunları değişkenler veya sabitler olarak ifade etmenin faydaları vardır .

Uzun cevap: Çoğu dil, sorununuzun alanına yakın olan türler sunar ve bunu yapmasalar bile, muhtemelen (vb.) 'Den leftfarklı bir varlık olarak tanımlayabileceğiniz bazı yöntemleri vardır right. Bunu kullanarak bir dizeye dönüştürmek "left", dilin ve IDE'nin hata denetimi gibi yararlı işlevlerinin kaybedilmesidir. Kullanmanız gerekse bile

left = "left";

veya eşdeğeri bir şey varsa, kodu kodunuzda belirttiğinizde dizeyi kullanmanın avantajları vardır. Örneğin,

if (player.direction == Left)

derleme zamanı hatası (en iyi durum, java ve benzeri) olarak algılanır veya bitlerine değen herhangi bir IDE tarafından yanlış (en kötü durum, temel ve benzeri) olarak işaretlenir.

Buna ek olarak, yönlendirilebilir leftbir varlık kavramına sahip olmak, yön türüne gitmeye karar verdiğiniz her yöne uyum sağlamanıza yardımcı olacaktır. Kullanarak "left", yön a String. Tür için daha iyi bir soyutlama bulursanız veya oluşturursanız, tüm kod gövdesini her örneğini değiştirerek avlamaya gitmeniz gerekir "left". Bir sabit veya değişken, tür ayrıntılandırılmışsa herhangi bir değişiklik gerektirmez.

Gerçekten istediğiniz tür, alan adınıza özgüdür. Kodunuz sizin için ne planlıyor left? Belki sola bakan veya ileriye doğru hareket eden bir doku veya hareketli grafiğin x eksenini yansıtmak istersiniz; öyleyse, leftbu davranışı yansıtan bir özelliğe veya yönteme sahip bir rightnesne , nesnenizin yansıtılmamış ters sonuca sahip olmasını isteyebilirsiniz . Bu mantığı, spriteları veya dokuları temsil eden bir nesnede yapabilirsiniz, bu durumda yukarıda belirtilen nedenler "left"yerine kullanmak için tekrar acı çekersiniz left.

Java'da (ve muhtemelen henüz bilmediğim diğer dillerde), enumiyi bir alternatiftir, çünkü Java'da, sınırlı bir örnek kümesiyle enumyararlıdır final class. Gerekirse davranışları tanımlayabilirsiniz ve dosya dışında herhangi bir sorun olmadan açık bir sınıfa geçebilirsiniz enum, ancak birçok dil enumbir ilkel tür olarak görür veya kullanmak için özel sözdizimi gerektirir. Bu, enumkaputu onunla hiçbir işi olmayan kodlara sızdırıyor ve daha sonra düzeltilmesi gerekebilir. enumSeçeneği düşünmeden önce dilinizin an kavramını anladığınızdan emin olun .


2

Dilinizi belirtmediniz, ancak genel bir cevap vermek için, metne gerçekten ihtiyacınız olduğunda, bir şeyi temsil etmemek için dizeleri kullanmalısınız. Örneğin verdiğiniz örnek, üretim yazılımında kabul edilemez.

Her dilin çeşitli temel veri türleri vardır ve görev için en uygun olanı kullanmalısınız. Örneğinizi kullanmak için, farklı durumları temsil etmek için sayısal sabitleri kullanabilirsiniz. Yani sol sıfır değerine sahip olabilir ve sağ bir olur. Bahsettiğiniz nedenin yanı sıra, sayısal değerler daha az yer kaplar (bellek) ve sayıları karşılaştırmak her zaman birden çok karakter dizesini karşılaştırmaktan daha hızlıdır.

Önerildiği gibi, diliniz izin veriyorsa numaralandırmaları kullanın. Özel örneğinizde, açıkça daha iyi bir seçimdir.


Hız ve hafızanın önemi yoktur. Bununla birlikte, enumları veya sabitleri tercih edin. Veriler, örneğin XML gibi bir metin biçiminden geliyorsa, dizeler daha mantıklıdır, ancak o zaman bile tüm büyük harflerle veya tüm büyük harflerle uyumludur. Veya, her zaman dönüştürün , e g. if (uppercase(foo) == "LEFT")
user949300

2
@ user949300 Dizeleri büyük harfe veya küçük harfe dönüştürmek de güvenilir değildir. Birinin Türkiye gibi başka bir yerel ayarı ziyaret etmeye (veya buradaki işletmeyi genişletmeye) ve saf üst kasa (veya alt kasa) dize karşılaştırmalarını kırma olasılığı vardır .
8bittree

Hız ve hafızayı önemsemek her zaman iyi bir uygulamadır, sonsuz kaynaklar değildir. Okunabilirlik veya başka bir değiş tokuş uğruna bilinçli olarak feda etmek uygun olsa da, burada durum böyle değildir. Ancak onları önemsememek, kolayca yavaş veya israflı uygulamalara yol açabilir.
Nagev

Dizeleri karşılaştırmak, sıralamaları karşılaştırmaktan 50 kat daha yavaştır. Çoğu zaman önemli değil. Ancak kodunuz zaten yavaş tarafta ise, bu fark onu kabul edilemez hale getirebilir. Daha da önemlisi, dizeleri kullanırsanız, derleyicinin yazım hatalarında size yardımcı olamamasıdır.
gnasher729

1

Durumunuzda anlamlı olan veri türünü kullanmanız yeterlidir.

Kullanımı stringaltta yatan arası / içi uygulama iletişim gibi, tip doğal bir sorun değildir. Aslında, bazen dizeleri kullanmak tercih edilir: Genel bir API'niz varsa, API'ya giren ve çıkan değerlerin insan tarafından okunabilir olması istenebilir. API'nizi kullanan kişilerin öğrenmesini ve hatalarını ayıklamasını kolaylaştırır.

Kodunuzdaki asıl sorun , değeri tekrar etmektir.

Bunu yapma:

if (direction == 'left') {
  goLeft();
}

Bu koşullardan birinde veya başka bir yerde "sol" kullanımda bir yazım hatası yaptıysanız, kod tabanı genelinde etkin bir arama yapamayabilirsiniz, çünkü yanlış yazdınız!

Bunun yerine, kullandığınız dilde / dillerde ihtiyacınız olan veri türünü destekleyen bir numaralandırmaya veya sabite karşı kodlayın.

Bu , başvurunuzda bir kez ve yalnızca bir kezLEFT atanması gerektiği anlamına gelir . Kodunuzun geri kalanı bu numaralandırmalardan veya sabitlerden yararlanmalıdır:

const string LEFT = "left";

if (direction == LEFT) {
  goLeft();
}

Bu ayrıca, daha sonra yol tarifleriniz için kullandığınız veri türünü daha kolay değiştirmenize olanak tanır.


1

Kötü uygulama mu?

Muhtemelen evet, ancak tam olarak ne yaptığınıza ve kullandığınız programlama diline bağlıdır.

Örneğinizde, bir yönün alabileceği küçük ve sonsuza dek sabit bir değer kümesi olduğunu çıkarabiliriz. Bu durumda, bir dize kullanmanın avantajları ve bazı dezavantajları yoktur. Bu örnek için:

  • enumProgramlama diliniz bunu destekliyorsa, bir tür tercih edilir.
  • Aksi takdirde, sabitler için tek bir tanımla adlandırılmış tamsayı sabitleri gidilecek yoldur.

Ancak, değerler kümesi dinamik olarak değiştirilebilirse veya zaman içinde gelişmesi gerekiyorsa , yanıt farklı olabilir . Çoğu dilde, bir enumtürün değiştirilmesi (örneğin, bir değer eklemek veya kaldırmak için) tam bir yeniden derleme gerektirir. (Örneğin, Java'daki bir enum değerini kaldırmak ikili uyumluluğu bozar.) Aynı durum adlandırılmış tamsayı sabitleri için de geçerlidir.

Bunun gibi senaryolarda başka bir çözüm gerekebilir ve dize kullanmak seçeneklerden biridir. (Ve dize değişmezlerini ve adlandırılmış sabitleri birleştirebilirsiniz ... senaryo dinamik uzantılarla sabit bir çekirdek gerektiriyorsa.)


Java'da character.direction == "left"uyguluyorsanız, başka bir nedenden dolayı kötü bir uygulamadır. ==Dizeleri karşılaştırmak için kullanmamalısınız , çünkü dize eşitliği yerine nesne kimliklerini test eder. ( "left"Dizenin tüm örneklerinin sabitlendiğini garanti edebilseydiniz , ancak bu tüm uygulama analizi gerektirir.)


1
Her zaman sabit gibi görünen şey, çoğu zaman bu kadar sabit değildir. Örneğin dört yön sekiz olabilir.
Jimmy T.

@JimmyT. - Bu bağlama bağlıdır. Örneğin, bir oyunda, bir karakterin 4'ten 8'e taşıyabileceği yön sayısını değiştirmek, oyun kurallarının ve kuralları uygulayan kodun tamamen revize edilmesini gerektirecektir. Yönleri Stringtemsil etmek, değişiklikleri yapmak için gereken iş miktarında sıfıra yakın bir fark yaratacaktır. Daha mantıklı bir yaklaşım, yönlerin sayısının değişmeyeceğini varsaymak ve oyun kuralları çok temelden değiştiyse her iki şekilde de yapacak çok işinizin olacağını kabul etmektir .
Stephen C

@JimmyT - Tamamen katılıyorum Bunun birçok kez olduğunu gördüm, ayrıca geliştiricilerin dizeyi yeniden tanımlamanın kısa yolunu alıyorsunuz, örneğin, ürün = "Seçenek" ürün = "Option_or_Future" kodun anlamını tamamen düşürüyor.
Chris Milburn

-3

Önerildiği gibi, Numaralandırmalar kullanmalısınız. Ancak, Enum'u Strigns'in yerine kullanmak yeterli IMHO değildir. Özel örneğinizde, oyuncu hızı aslında fizik yoluyla bir vektör olmalıdır:

class Vector {
  final double x;
  final double y;
}

Bu vektör daha sonra her bir işaretin oyuncu konumunu güncellemek için kullanılmalıdır.

Daha sonra daha yüksek okunabilirlik için bunu bir numaralandırma ile birleştirebilirsiniz:

enum Direction {
  UP(new Vector(0, 1)),
  RIGHT(new Vector(1, 0)),
  DOWN(new Vector(0, -1)),
  LEFT(new Vector(-1, 0));

  private Vector direction;

  Direction(Vector v) {
    this.direction = v;
  }

  public Vector getVector() { return this.direction; }
}

4
-1 Verdiği örneğe çok fazla gidiyorsunuz.
Pieter B
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.