Java'da bir sabitler sınıfını nasıl tanımlarsınız?


90

Tüm yaptığı sabitleri tutan bir sınıf tanımlamanız gerektiğini varsayalım.

public static final String SOME_CONST = "SOME_VALUE";

Bunu yapmanın tercih edilen yolu nedir?

  1. Arayüz
  2. Soyut Sınıf
  3. Final Sınıfı

Hangisini kullanmalıyım ve neden?


Bazı cevapların açıklamaları:

Numaralamalar - Ben sadece herhangi bir şekilde birbiriyle ilişkili olmayan bazı sabitleri toplayarak, hiçbir şey numaralandırma değilim, Çeteleler kullanmak için gitmiyorum.

Arayüz - Arayüzü uygulayan bir sınıf olarak herhangi bir sınıf ayarlamayacağım. Sadece şöyle sabitleri çağırmak için arayüz kullanmak istiyorum: ISomeInterface.SOME_CONST.


Burada benzer bir tartışma var: stackoverflow.com/questions/320588/… . Özel bir kurucuya sahip bir son sınıf kullanırdım, böylece örneklenemez.
Dan Dyer

2
Üzgünüm ama "Numaralandırmayacağım" bu soruyu "aptalca bir şey yapmanın en iyi yolu nedir?"
cletus

Arayüzü uygulayacağınızı söylemiyorum. Ancak bunu yapmak için bir arayüz kullanmanın bir anlamı yok. Öyleyse, son sınıfa
geçin :)

Enum ile ilgili sorun nedir? Her zaman, 'birbiriyle hiçbir şekilde ilişkili olmayan bazı sabitleri' toplamak için kullanabilirsiniz. Hmm?
gedevan

6
Kavramsal olarak, sabitler ilişkili değilse enum kötü bir seçimdir. Bir enum, aynı türden alternatif değerleri temsil eder. Bu sabitler alternatif değildir ve hatta aynı türde olmayabilir (bazıları dizeler, bazı tamsayılar vb.
Olabilir

Yanıtlar:


94

Son bir sınıf kullanın. Basit olması için, değerlerinizi başka bir sınıfta yeniden kullanmak için statik bir içe aktarma kullanabilirsiniz.

public final class MyValues {
  public static final String VALUE1 = "foo";
  public static final String VALUE2 = "bar";
}

başka bir sınıfta:

import static MyValues.*
//...

if(variable.equals(VALUE1)){
//...
}

4
Burada ayrı bir sınıf oluşturmanın faydası nerede? Normalde Takvim API'sini iyi bir tasarım örneği olarak tutmasam da, "takvimle ilgili sabitler Takvim sınıfındadır" açısından sorun değil.
Jon Skeet

7
bunun faydası, sabitleri birden fazla sınıfta yeniden kullanmanız gerekmesi durumunda, kodu kopyalamamaktır. Sanırım bunun avantajını kolayca görebiliyorsunuz.
user54579

2
Kodu neden kopyalıyorsunuz? Sadece diğer sınıfa bakın. Bir sabitin gerçekten tek başına durmasını nispeten nadir buluyorum.
Jon Skeet

14
Daha iyi okunabilirlik için gövdesi olmayan (ve eşleşen bir yorumu) özel bir varsayılan kurucum da olurdu.
Ran Biron

5
Oldukça eski bir cevap ve bu yorum muhtemelen yerinde değil, ancak VALUE1.equals(variable)NPE'yi önlediği için kullanırım .
Aakash

38

Açıklamanız şöyle diyor: "Numaralandırma kullanmayacağım, hiçbir şey saymıyorum, sadece birbiriyle hiçbir şekilde ilişkili olmayan bazı sabitleri topluyorum."

Sabitler birbirleriyle hiç ilişkili değilse, neden onları bir araya toplamak istiyorsun? Her sabiti en yakın ilişkili olduğu sınıfa koyun.


2
Jon - hepsi aynı işlevselliğe ait olmaları bakımından birbirleriyle ilişkilidirler. Ancak bunlar hiçbir şeyin sıralaması değildir ... Bir nesnenin "bunlardan biri" olduğu özelliğini taşımazlar.
Yuval Adam

13
Tamam. Bu durumda, onları ilgili oldukları işleve en yakın sınıfa koyun.
Jon Skeet

28

Önerilerim (azalan tercih sırasına göre):

1) Yapma . Sabitleri gerçek sınıfta en alakalı oldukları yerde oluşturun. Bir 'sabitler çantası' sınıfına / arayüzüne sahip olmak, OO en iyi uygulamalarını gerçekten takip etmiyor.

Ben ve diğer herkes zaman zaman # 1'i görmezden gelirim. Bunu yapacaksan o zaman:

2) özel kurucu ile son sınıf Bu, en azından, sabitlere kolay erişim sağlamak için genişleterek / uygulayarak 'sabitler çantanızı' kötüye kullanmasını engelleyecektir. (Bunu yapmayacağını söylediğini biliyorum - ama bu, senden sonra birinin geleceği anlamına gelmez)

3) arayüz Bu işe yarayacak, ancak benim 2. maddede olası kötüye kullanımdan bahsetme tercihim değil.

Genel olarak, bunların sabit olması, onlara normal oo ilkelerini uygulamaman gerektiği anlamına gelmez. Bir sınıf dışında hiç kimse bir sabiti umursamıyorsa - özel ve o sınıfta olmalıdır. Sadece testler bir sabiti önemsiyorsa - üretim kodunda değil, bir test sınıfında olmalıdır. Bir sabit birden fazla yerde tanımlanmışsa (sadece yanlışlıkla aynı değil) - tekrarlamayı ortadan kaldırmak için yeniden düzenleyin. Ve benzeri - onlara bir yöntem gibi davranın.


2
1'in sorunu, bazen sabiti almak için kodunuza bazı bağımlılıkları başka bir katman sınıfına enjekte edeceğinizdir.
amdev

Bir arayüzdeki tüm alanlar örtük olarak herkese açık, statik ve nihaidir
Kodebetter

@Kodebetter Ancak arayüzler daha fazla alan eklemek için genişletilebilir / uygulanabilir.
Zekâ

12

Joshua Bloch'un Etkili Java'da belirttiği gibi:

  • Arayüzler yalnızca türleri tanımlamak için kullanılmalıdır,
  • soyut sınıflar tutarsızlığı engellemez (alt sınıflara ayrılabilirler ve hatta alt sınıflara alınmak üzere tasarlandıklarını öne sürerler).

Tüm sabitleriniz ilişkiliyse (gezegen adları gibi), sabit değerleri ilişkili oldukları sınıflara (bunlara erişiminiz varsa) koyabilir veya kalıcı olmayan bir yardımcı sınıf (özel bir varsayılan kurucu tanımlayın) kullanabilirsiniz. .

class SomeConstants
{
    // Prevents instanciation of myself and my subclasses
    private SomeConstants() {}

    public final static String TOTO = "toto";
    public final static Integer TEN = 10;
    //...
}

Ardından, daha önce de belirtildiği gibi, sabitlerinizi kullanmak için statik içe aktarmaları kullanabilirsiniz.


7

Benim tercih ettiğim yöntem bunu hiç yapmamak. Sabitlerin yaşı, Java 5, typafe numaralandırmalarını tanıttığında hemen hemen öldü. Ve o zamandan önce bile Josh Bloch, Java 1.4 (ve öncesi) üzerinde çalışan (biraz daha uzun) bir sürümünü yayınladı.

Bazı eski kodlarla birlikte çalışabilirliğe ihtiyacınız olmadığı sürece, adlandırılmış Dize / tamsayı sabitlerini kullanmak için gerçekten hiçbir neden yoktur.


2
Güzel cevap, bir örnek daha iyi olurdu.
amdev

3

Sadece son sınıfı kullanın.

Başka değerler ekleyebilmek istiyorsanız, soyut bir sınıf kullanın.

Bir arayüz kullanmak pek mantıklı değil, bir arayüzün bir sözleşme belirtmesi gerekiyor. Sadece bazı sabit değerler beyan etmek istiyorsunuz.



3

enumiyi. IIRC, etkili Java'daki (2. Baskı) bir öğe, herhangi bir değer için enumbir [Java anahtar sözcüğü] uygulayan standart seçenekleri sıralayan sabitlere sahiptir interface.

Tercihim bir [Java anahtar kelime] kullanmaktır interfacebir aşkın final classsabitleri için. Örtük olarak public static final. Bazı insanlar, interfacekötü programcıların onu uygulamasına izin verdiğini iddia edecek , ancak kötü programcılar ne yaparsanız yapın berbat bir kod yazacaklar.

Hangisi daha iyi görünüyor?

public final class SomeStuff {
     private SomeStuff() {
         throw new Error();
     }
     public static final String SOME_CONST = "Some value or another, I don't know.";
}

Veya:

public interface SomeStuff {
     String SOME_CONST = "Some value or another, I don't know.";
}

ama kötü programcılar ne yaparsanız yapın berbat bir kod yazacaklar. Bu sadece çok doğru. Kötü programlamayı azaltmak için adımlar atabilir veya tamamen ortadan kaldırabilirseniz, bunu yapmak için biraz sorumluluğunuz vardır; olabildiğince açık olun. Kötü bir programcı son bir sınıfı uzatamaz.
liltitus27

1
@ liltitus27 Bir dereceye kadar katılıyorum. Ama gerçekten kötü programcıların kötü kod yazmasını engellemek için çirkin bir kod mu istiyorsun? Ürettikleri kod hala umutsuz olacak, ancak şimdi kodunuz daha az okunabilir.
Tom Hawtin - tackline

1

Veya 4. Onları, sabitleri en çok kullanan mantığı içeren sınıfa koyun.

... üzgünüm, dayanamadım ;-)


3
Bu iyi bir fikir değil. Bu, hiç olmaması gereken sınıflar arasında bağımlılıklar yaratır.
Yuval Adam

Neden olmasın? Aynı sabitleri kullanan sınıfların zaten bir bağımlılığı olduğunu söyleyebilirim ... Ve bir şekilde bu sabitlere en fazla bağımlı olan bir sınıf olmalı.
Simon Groenewolt

Sabitleri kullanan yalnızca bir sınıf varsa, bu mantıklı olabilir.
Tom Hawtin - tackline

-1
  1. Özel kurucunun dezavantajlarından biri, yöntemin varlığının asla test edilememesidir.

  2. Doğası gereği numaralandırma kavramı belirli bir alan türünde uygulamak iyidir, merkezi olmayan sabitlere uygulamak yeterince iyi görünmüyor

Enum kavramı "Numaralandırmalar yakından ilişkili öğeler kümesidir".

  1. Sabit bir arabirimi genişletmek / uygulamak kötü bir uygulamadır, doğrudan ona atıfta bulunmak yerine değişmez bir sabiti genişletme gerekliliğini düşünmek zordur.

  2. SonarSource gibi kaliteli bir araç uygularsanız, geliştiriciyi sabit arabirimi bırakmaya zorlayan kurallar vardır, bu garip bir şeydir, çünkü birçok proje sabit arabirimden yararlanır ve nadiren sürekli arabirimlerde "genişleyen" şeylerin gerçekleştiğini görür.


1
"özel kurucu, yöntemin varlığı asla test edilemez": doğru değil. Siz (veya patronunuz) kod kapsamı raporlarının% 100 olması konusunda gerçekten paranoyak iseniz, bunu yansıtma kullanarak ve yapıcının bir istisna atmasını sağlayarak yine de test edebilirsiniz. Ancak IMHO, bu sadece formalite ve gerçekten test edilmesine gerek yok. Siz (veya takım) yalnızca gerçekten önemli olanı umursuyorsa,% 100 kapsama alanı gerekli değildir.
L. Holanda
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.