Dize temsillerini kolaylaştırmak için numaralandırmalar için tümüyle büyük harf adlandırmalarına karşı çıkmak uygun mudur?


14

Birkaç kez insanların enum sabitleri için başlık veya hatta tüm küçük harf adlandırma kullandığını gördüm, örneğin:

enum Color {
  red,
  yellow,
  green;
}

Bu, örneğin dize formlarıyla çalışmayı basit ve kolay hale getirir throw new IllegalStateException("Light should not be " + color + ".").

Enum ise bu daha kabul edilebilir görünüyor private, ama yine de hoşlanmıyorum. Ben bir dize alanı ile bir numaralandırma yapıcı yapabilir ve daha sonra bu gibi bu adı döndürmek için toString geçersiz kılabilir biliyorum:

enum Color {
  RED("red"),
  YELLOW("yellow"),
  GREEN("green");

  private final String name;

  private Color(String name) { 
    this.name = name 
  }

  @Override public String toString() {
    return name; 
  }
}

Ama ne kadar uzun olduğuna bakın. Basit tutmak istediğiniz küçük küçük numaralarınız varsa yapmaya devam etmek sinir bozucu. Burada alışılmadık vaka formatlarını kullanmak uygun mudur?


4
Bu bir kongre. Sözleşmeyi kırmak için bir nedeniniz var mı? Sana bağlı.

9
Sadece bir istisna mesajı ile neyin yanlış olduğunu merak ediyorum Light should not be RED.. Sonuçta, bu mesaj geliştirici içindir, kullanıcı asla görmemelidir.
Brandin

1
@Renk, bir uygulama detayından daha fazla ise, kimse onu görmemelidir. Tabii ki, sanırım bu neden güzel bir forma ihtiyacımız olduğu sorusunu bırakıyor.
kod kırıcı

8
Günün sonunda size kalmış. Kodunuzda hata ayıklama ve bir istisna mesajı gördüm bir Light should not be YELLOW.tür sabit olduğunu tahmin ediyorum, toString () yöntemi sadece hata ayıklama amaçlı olduğunu, bu yüzden neden bu iletinin nasıl göründüğünü değiştirmek gerektiğini görmüyorum.
Brandin

1
Bence cevap daha çok 'tamam' fikrinize dayanıyor. Dünya, büyük olasılıkla, bunu yaparsanız alevlere patlamaz ve hatta bir programı başarıyla yazabilirsiniz. Yararlı mı? meh çok öznel. Biraz fayda görürseniz, sizin için buna değer mi ve başkalarını etkileyecek mi? Bunlar umursadığım sorular.
Garet Claborn

Yanıtlar:


14

Kısa cevap sizden aktaran ... esasen sabitlerdir ne için adlandırma ile kırmak isteyip, tabii ki JLS :

Sabit İsimler

Arabirim türlerindeki sabitlerin adları olmalıdır ve sınıf türlerinin son değişkenleri geleneksel olarak, alt çizgi "_" karakterleri ile ayrılmış bileşenlerle birlikte bir veya daha fazla kelime, kısaltma veya kısaltmadan oluşan bir dizi olabilir. Sabit isimler açıklayıcı olmalı ve gereksiz yere kısaltılmamalıdır. Geleneksel olarak konuşmanın uygun herhangi bir parçası olabilirler.

Uzun cevap, kullanımı ile ilgili olarak , değerlerin toString()daha okunabilir bir temsilini istiyorsanız kesinlikle geçersiz kılma yöntemidir enum. Alıntı yapan Object.toString()(benim vurgu):

Nesnenin dize olarak temsilini döndürür. Genel olarak, toStringyöntem bu nesneyi "metinsel olarak" temsil eden bir dize döndürür . Sonuç, bir kişinin okuması kolay, kısa ama bilgilendirici bir temsil olmalıdır . Tüm alt sınıfların bu yöntemi geçersiz kılması önerilir.

Şimdi, bazı cevapların neden değerlerle enumsileri geri dönüş hakkında konuşmaya sürüklendiğinden emin değilim String, ama burada da benim yerimi alacağım. enumDeğerlerin bu şekilde serileştirilmesi , name()veya ordinal()yöntemleri kullanılarak kolayca halledilebilir . Her ikisi de vardır finalve bu nedenle değerlerin adları veya konumları değişmediği sürece döndürülen değerlerden emin olabilirsiniz . Bana göre, bu yeterince açık bir işaret.

Yukarıdakilerden topladığım şey: bugün, YELLOWsadece "sarı" olarak tanımlamak isteyebilirsiniz . Yarın, "Pantone Minion Yellow" olarak tanımlamak isteyebilirsiniz . Bu açıklamalar çağrıdan döndürülmeli toString()ve ben de ya name()da ordinal()değişmeyi beklemem . Bunu yaparsam, kod tabanımda veya ekibimde çözmem gereken bir şeydir ve sadece bir enumadlandırma stilinden daha büyük bir soru haline gelir .

Sonuç olarak, tek yapmanız gereken değerlerinizin daha okunabilir bir temsilini kaydetmekse enum, yine de kurallara bağlı kalmanızı ve ardından geçersiz kılmanızı öneririm toString(). Bunları bir veri dosyasına veya diğer Java dışı hedeflere serileştirmek istiyorsanız, yine de sizi yedeklemek için name()ve ordinal()yöntemleriniz vardır, bu nedenle geçersiz kılma konusunda endişelenmenize gerek yoktur toString().


5

Bu ENUMsadece kötü kod kokusu değiştirmeyin. Bir enum bir enum ve bir dize bir dize olsun.

Bunun yerine, dize değerleri için bir CamelCase dönüştürücü kullanın.

throw new IllegalStateException("Light should not be " + CamelCase(color) + ".");

Java için bu sorunu zaten çözen birçok açık kaynak kitaplığı vardır.

http://docs.guava-libraries.googlecode.com/git/javadoc/com/google/common/base/CaseFormat.html


Bazı uç durumlarda belirleyici olmaz mıydı? (belirli bir dönüştürücünün davranışı değil, genel prensip)
Panzercrisis

-1 Temel Dize biçimlendirmesi için istediğiniz gibi bir üçüncü taraf kitaplığı eklemek aşırı olabilir.
user949300

1
@ user949300 kodu kopyalayın, kendiniz veya ne yazdığınızı yazın. Konuyu kaçırıyorsun.
Reactgular

"Konuyu" biraz açıklayabilir misiniz? "Bir numaralandırma bir numaralandırma ve bir dize bir dize olsun" kulağa hoş geliyor, ama bu gerçekten ne anlama geliyor?
user949300

1
Enum tip güvenliği sağlar. Renk olarak "patates" i geçemez. Ve belki, enum'da RGB değeri gibi diğer verileri içerir, sadece kodda göstermez. Dize yerine bir numaralandırma kullanmak için birçok iyi neden vardır.
user949300

3

Java kodum ile bir veritabanı veya istemci uygulaması arasında numaralandırma gönderirken, genellikle numaralandırma değerlerini okuma ve dizgiler olarak yazma. toString()dizeleri birleştirirken örtük olarak çağrılır. Bazı numaralarda toString () geçersiz kılmak, bazen sadece

"<input type='checkbox' value='" + MY_CONST1 + "'>"

ve bazen aramayı hatırlamak zorunda kaldım

"<input type='checkbox' value='" + MY_CONST1.name() + "'>"

bu da hatalara yol açtı, bu yüzden artık bunu yapmıyorum. Aslında, Enum'da herhangi bir yöntemi geçersiz kılmam çünkü onları yeterli müşteri koduna atarsanız, sonunda birinin beklentilerini kıracaksınız.

Kendi yönteminizin adını public String text()veya benzeri toEnglish()herhangi bir şeyi yapın.

Yukarıdaki gibi çok sayıda numaralandırma varsa size bazı yazmayı kurtarabilecek küçük bir yardımcı işlev:

public static String ucFirstLowerRest(String s) {
    if ( (s == null) || (s.length() < 1) ) {
        return s;
    } else if (s.length() == 1) {
        return s.toUpperCase();
    } else {
        return s.substring(0, 1).toUpperCase() + s.substring(1).toLowerCase();
    }
}

.ToUpperCase () veya .toLowerCase () öğesini çağırmak her zaman kolaydır, ancak karışık durumu geri almak zor olabilir. "Bleu de France" rengini düşünün. Fransa her zaman büyük harfle yazılır, bu nedenle numaralandırmanızda numaralandırmanıza bir textLower () yöntemi eklemek isteyebilirsiniz. Bu metni bir cümlenin başında, bir cümlenin ortasına veya bir başlığa kullandığınızda, tek bir toString()yöntemin nasıl kısa süreceğini görebilirsiniz. Ve bu, Java tanımlayıcılarında yasadışı olan veya yazılması zor olan karakterlere, standart klavyelerde temsil edilmediğinden veya büyük / küçük harf içermeyen karakterlere (Kanji, vb.) Bile dokunmaz.

enum Color {
  BLEU_DE_FRANCE {
    @Override public String textTc() { return "Bleu De France"; }
    @Override public String textLc() { return "bleu de France"; }
  }
  CAFE_NOIR {
    @Override public String textTc() { return "Café Noir"; }
  }
  RED,
  YELLOW,
  GREEN;

  // The text in title case
  private final String textTc;

  private Color() { 
    textTc = ucFirstLowerRest(this.toString());
  }

  // Title case
  public String textTc() { return textTc; }

  // For the middle of a sentence
  public String textLc() { return textTc().toLowerCase(); }

  // For the start of a sentence
  public String textUcFirst() {
    String lc = textLc();
    return lc.substring(0, 1).toUpperCase() + lc.substring(1);
  }
}

Bunları düzgün kullanmak çok zor değil:

IllegalStateException(color1.textUcFirst() + " clashes horribly with " +
                      color2.textLc() + "!")

Umarım bu da karışık vaka enum değerlerinin kullanılmasının neden sizi hayal kırıklığına uğratacağını gösterir. Alt çizgileri saymak sabitleri ile tüm kapaklar tutmak için son bir nedeni, bunu En Az Şaşkınlık Prensibi takip olmasıdır. İnsanlar bunu bekler, bu yüzden farklı bir şey yaparsanız, her zaman kendinizi açıklamak veya kodunuzu kötüye kullanan insanlarla uğraşmak zorunda kalacaksınız.


3
toString()Bir enum üzerinde asla geçersiz kılma önerisi benim için hiçbir anlam ifade etmiyor. Numaralandırma adlarının garantili varsayılan davranışını istiyorsanız, tuşunu kullanın name(). Ben toString()doğru anahtarı sağlamak için güvenmek için hiç "cazip" bulamıyorum valueOf(String). Sanırım numaralarınızı aptal geçirmez yapmak istiyorsanız, bu bir şey, ama bunun asla geçersiz kılmamanızı tavsiye etmek için yeterince iyi bir neden olduğunu düşünmüyorum toString().
kod kırıcı

1
Ayrıca, enum'da toString'in geçersiz kılmasının aslında iyi bir şey olduğunu (inandığım gibi) öneren bunu buldum: stackoverflow.com/questions/13291076/…
kod kırıcı

@codebreaker toString (), dizeleri birleştirirken örtük olarak çağrılır. Bazı numaralarda toString () geçersiz <input type='checkbox' value=" + MY_CONST1 + ">kılmak, bazen sadece ve bazen aramayı hatırlamak zorunda olduğum anlamına geliyordu, bu da <input type='checkbox' value=" + MY_CONST1.name() + ">hatalara yol açtı.
GlenPeterson

Tamam, bu iyi bir nokta, ama sadece kendi adlarıyla numaralandırma "serileştirmek" zaman önemlidir (bu benim örnek ile endişelenmem gereken şey değil).
kod kırıcı

0

Bu dize temsillerinin veritabanları veya metin dosyaları gibi yerlerde saklanma şansı en düşükse, enum sabitlemelerinize bağlı olmaları, enumunuzu yeniden düzenlemeniz gerekirse çok sorunlu olacaktır.

Ya Yeniden adlandırmak karar bir gün Color.Whiteiçin Color.TitaniumWhiteveri "Beyaz" içeren orada dosyalar varken?

Ayrıca, enum sabitlerini dizelere dönüştürmeye başladığınızda, bir sonraki adım, kullanıcının görmesi için dizeler oluşturmak olacaktır ve burada sorun, bildiğiniz gibi, java sözdiziminin tanımlayıcılar içindeki boşluklara izin ver. (Asla sahip olamayacaksınız Color.Titanium White.) Yani, kullanıcıya göstermek için numaralandırma adları oluşturmak için muhtemelen uygun bir mekanizmaya ihtiyacınız olacağından, enumunuzu gereksiz yere karmaşıklaştırmaktan kaçınmak en iyisidir.

Bunu söyledikten sonra, elbette devam edip ne yapmayı düşündüğünüzü yapabilir ve daha sonra numaralandırmayı daha sonra, sorun yaşarsanız (ve eğer), kurucuya isimleri aktarmak için yeniden düzenleyebilirsiniz.

nameAlanı ilan public finaledip alıcıyı kaybederek, numaralandırıcı-kurucu ile birkaç çizgiyi tıraş edebilirsiniz . (Java programcılarının alıcılara karşı duyduğu bu aşk nedir?)


Bir genel son statik, geldiği sınıfa referans olarak değil, gerçek sabit olarak kullanan koda derlenir. Bu, kodun kısmi olarak yeniden derlenmesi (veya bir kavanozun değiştirilmesi) sırasında bir dizi eğlenceli hataya neden olabilir. Eğer öneriyorsanız public final static int white = 1;veya public final static String white = "white";(konvansiyonun yeniden kırılmasının yanı sıra), bu numaralandırmanın sağladığı tip güvenliğini kaybeder.

@MichaelT Enum alanları statik değildir. Her numaralandırma sabiti için bir örnek oluşturulur ve numaralandırmanın üyeleri bu örneğin üye değişkenleridir. public finalOluşturucudan başlatılan bir örnek alanı , derleme zamanında ona atamanızın engellenmesi dışında, son olmayan bir alan gibi davranır . Yansımayı kullanarak değiştirebilirsiniz ve ona karşılık gelen tüm kodlar hemen yeni değeri görmeye başlar.
Mike Nakis

0

Tartışmalı olarak, UPPERCASE adlandırma kuralını izleyerek KURU ihlal edilir . (Ve YAGNI ). örneğin, kod örneğinizde # 2: "KIRMIZI" ve "kırmızı" tekrarlanır.

Peki, resmi sözleşmeyi mi takip ediyorsunuz yoksa DRY'yi mi takip ediyorsunuz? Çağrınız.

Kodumda, DRY'yi takip edeceğim. Ancak, Enum sınıfına "hepsi büyük harf değil çünkü (burada açıklama)" diyerek bir yorum yapacağım

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.