Singleton'u bir Enum ile Uygulama (Java'da)


178

Böyle Singletonbir kullanarak Java uygulamak mümkün olduğunu okudum Enum:

public enum MySingleton {
     INSTANCE;   
}

Ancak, yukarıdaki nasıl çalışır? Özellikle, bir Objectsomutlaştırılmalıdır. Burada nasıl MySingletonsomutlaştırılıyor? Kim yapıyor new MySingleton()?


24
Kim yeni MySingleton () yapıyor JVM.
Sotirios Delimanolis

37
INSTANCEile aynıdır public static final MySingleton INSTANCE = new MySingleton();.
Pshemo

6
ENUM - Garantili bir singleton.
Hata değil

Dzone.com/articles/java-singletons-using-enum , neden diğer yöntemleri değil, enum kullanıldığını okuyun . Kısa: Serileştirme ve yansıtma kullanılırken sorunlar başlar.
Miyagi

Yanıtlar:


203

Bu,

public enum MySingleton {
  INSTANCE;   
}

örtük bir boş kurucuya sahip. Bunun yerine açık yapın,

public enum MySingleton {
    INSTANCE;
    private MySingleton() {
        System.out.println("Here");
    }
}

Daha sonra main()benzer bir yöntemle başka bir sınıf eklediyseniz

public static void main(String[] args) {
    System.out.println(MySingleton.INSTANCE);
}

Görürdün

Here
INSTANCE

enumalanları derleme zaman sabitleridir, ancak türlerinin örnekleridir enum. Ve, enum türüne ilk kez başvurulduğunda yapılandırılırlar .


13
Varsayılan olarak numaralandırmaların örtülü özel kurucuya sahip olduğunu ve bu kurucuda çalıştırmanız gereken koda sahip olmadıkça açıkça özel bir kurucu eklemeye gerek olmadığını eklemelisiniz
Nimrod Dayan

her numaralandırma alanı yalnızca bir kez bir örnek oluşturur, bu nedenle özel oluşturucu oluşturmanıza gerek yoktur.
Pravat Panda

2
public enum MySingleton {INSTANCE, INSTANCE1; } ve ardından System.out.println (MySingleton.INSTANCE.hashCode ()); System.out.println (MySingleton.INSTANCE1.hashCode ()); farklı hashcode'lar basar. MySingleton'un iki nesnesinin yaratıldığı anlamına mı geliyor?
scott miles

@scottmiles Evet. Çünkü iki örneğiniz var. Bir singletonun tanımı gereği bir tane vardır.
Elliott Frisch

privateModifiye bir için bir anlama sahip enumyapıcı ve tamamen gereksizdir.
Dmitri Nesteruk

76

Bir enumtür özel bir türdür class.

Kişisel enumirade aslında böyle bir şeye derlenmiş

public final class MySingleton {
    public final static MySingleton INSTANCE = new MySingleton();
    private MySingleton(){} 
}

Kodunuz ilk kez eriştiğinde INSTANCE, sınıf MySingletonJVM tarafından yüklenecek ve başlatılacaktır. Bu işlem staticyukarıdaki alanı bir kez (tembel olarak) başlatır .


Bu sınıf ayrıca özel yapıcı () da içerecek mi? Bence olur
Yasir Shabbir Choudhary

public enum MySingleton { INSTANCE,INSTANCE1; }ve sonra System.out.println(MySingleton.INSTANCE.hashCode()); System.out.println(MySingleton.INSTANCE1.hashCode());farklı hashcode'lar basar. MySingleton'un iki nesnesinin yaratıldığı anlamına mı geliyor?
scott miles

2
@scottmiles Evet, bu sadece iki fark enumsabiti.
Sotirios Delimanolis


@SotiriosDelimanolis, enum thread ile bu yaklaşım güvenli midir?
abg

63

Joshua Bloch'un bu Java en iyi uygulamalar kitabında , Singleton özelliğini neden özel bir kurucu veya Enum türüyle zorlamanız gerektiğini açıklayan bulabilirsiniz. Bölüm oldukça uzundur, bu yüzden özetleyin:

Bir sınıfı Singleton yapmak müşterilerini test etmeyi zorlaştırabilir, çünkü türü olarak hizmet veren bir arabirim uygulamadığı sürece bir single uygulaması yerine sahte bir uygulama koymak imkansızdır. Önerilen yaklaşım, tek elemanlı bir enum tipi yaparak Singletons uygulamaktır:

// Enum singleton - the preferred approach
public enum Elvis {
INSTANCE;
public void leaveTheBuilding() { ... }
}

Bu yaklaşım, kamusal alan yaklaşımına işlevsel olarak eşdeğerdir, ancak daha özlü olması, serileştirme makinelerini ücretsiz olarak sağlaması ve sofistike serileştirme veya yansıma saldırıları karşısında bile çoklu somutlaşmaya karşı zırhlı bir garanti sağlar.

Bu yaklaşım henüz geniş çapta benimsenmese de, tek elemanlı bir enum tipi bir singletonu uygulamanın en iyi yoludur.


Bence, bir singletonu test edilebilir yapmak için bir strateji kalıbı kullanabilir ve tüm singleton eylemlerinin stratejiden geçmesini sağlayabilirsiniz. Böylece bir "üretim" stratejiniz ve bir "test" stratejiniz olabilir ...
Erk

9

Tüm numaralandırma örnekleri gibi, Java da sınıf yüklendiğinde her nesneyi başlatır ve JVM başına tam olarak bir kez başlatıldığını garanti eder . INSTANCEBildirimi herkese açık statik bir son alan olarak düşünün : Java, sınıfın ilk kez başvurulmasında nesneyi başlatır.

Örnekler, Java Dil Belirtimi, bölüm 12.4'te tanımlanan statik başlatma sırasında oluşturulur .

Ne 's değerinde için, Joshua Bloch 3. maddesinde olarak detaylı bir şekilde bu deseni açıklar Etkili Java Second Edition .


6

Yana Singleton Pattern özel yapıcı olan ve (bazıları gibi instantiations kontrol etmek için bazı yöntemini çağırarak hakkında getInstance), numaralamalar içinde zaten örtük bir özel yapıcı vardır.

JVM veya bazı konteynerin bizim örneklerini nasıl kontrol ettiğini tam olarak bilmiyorum Enums, ama zaten örtük bir kullanım kullandığına benziyor Singleton Pattern, fark bir biz getInstancedemiyoruz, sadece Enum diyoruz.


3

Daha önce de belirtildiği gibi, bir enum, tanımının en az bir "enum sabiti" ile başlaması gereken özel koşulu olan bir java sınıfıdır.

Bunun dışında ve numaralandırmalar genişletilemez veya diğer sınıfları genişletmek için kullanılamaz, bir numaralandırma herhangi bir sınıf gibi bir sınıftır ve bunu sabit tanımların altına yöntemler ekleyerek kullanırsınız:

public enum MySingleton {
    INSTANCE;

    public void doSomething() { ... }

    public synchronized String getSomething() { return something; }

    private String something;
}

Singleton'un yöntemlerine şu satırlardan erişirsiniz:

MySingleton.INSTANCE.doSomething();
String something = MySingleton.INSTANCE.getSomething();

Sınıf yerine bir enum kullanımı, diğer cevaplarda belirtildiği gibi, çoğunlukla singletonun iş parçacığıyla güvenli bir şekilde başlatılması ve her zaman sadece bir kopya olacağının garantisidir.

Ve belki de en önemlisi, bu davranışın JVM'nin kendisi ve Java spesifikasyonu tarafından garanti edildiğini.

Java belirtiminden bir numaralandırma örneğinin birden çok örneğinin nasıl önlendiğine ilişkin bir bölüm aşağıda verilmiştir :

Bir enum türünün, enum sabitleri tarafından tanımlananlardan başka bir örneği yoktur. Bir numaralandırma türünü açıkça başlatmaya çalışmak bir derleme zamanı hatasıdır. Enum'daki son klon yöntemi, enum sabitlerinin asla klonlanmamasını ve serileştirme mekanizmasının özel muamelesi, serileştirmenin bir sonucu olarak asla yinelenen örneklerin oluşturulmamasını sağlar. Enum tiplerinin yansıtıcı örneklenmesi yasaktır. Birlikte, bu dört şey, enum sabitleri tarafından tanımlananların ötesinde bir enum tipi örneklerin bulunmamasını sağlar.

Dikkat edilmesi gereken nokta, somutlaştırmadan sonra, herhangi bir iş parçacığı güvenliği endişesinin, senkronize edilmiş anahtar kelime vb. İle herhangi bir sınıfta olduğu gibi ele alınması gerektiğidir.

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.