Enforce the singleton property with a private constructor or an enum type

A singleton is simply a class that is instantiated exactly once. Singletons typically represent a system component that is intrinsically unique, such as the window manager or file system. Making a class a singleton can make it difficult to test its clients, as it’s impossible to substitute a mock implementation for a singleton unless it implements and interface that serves as its type.

// Singleton with public final field
public class Elvis {
  public static final Elvis INSTANCE = new Elvis();
  private Elvis() { // good practice to thrown an exception in case someone will try to invoke this with reflection }
  public void leaveTheBuilding() { }
}

The lack of a public or protected constructor guarantees a “monoelvistic” universe.

A second approach to implementing singletons is to expose a static factory method:

// Singleton with a static factory
public class Elvis {
  private static final Elvis INSTANCE = new Elvis();
  private Elvis() { // good practice to thrown an exception in case someone will try to invoke this with reflection }
  public static getInstance() { return INSTANCE; }
  public void leaveTheBuilding() { }
}

The main advantage of the public field approach is that the declarations make it clear that the class is a singleton, the public static field is final, so it will always contain the same object reference.

There is no any performance advantage of the public field approach, modern JVM implementations are almost certain to inline the call to the static factory method.

One advantage of the factory-method approach is that it gives you the flexibility to change your mind about whether the class should be a singleton without changing its API. The factory method returns the sole instance but could easily be modified to return, say, a unique instance for each thread that invokes it.

To make a singleton class serializable it is not enough to add implements Serializable. To maintain the singleton guarantee, you have to declare all instance fields transient and provide a readResolve method. Otherwise, each time a serialized instance is deserialized, a new instance will be created.

// readResolve method to preserve singleton property
private Object readResolve() {
  // Return the one true Elvis and let the garbage collector
  // take care of the Elvis impersonator.
  return INSTANCE;
}

There are few problems with singletons, Serialization and Deserialization, some one could use Reflection to try to obtain an instance.

To avoid mentioned problems, we can use Enums in order to create singletons. Enums are inherently serializable, we don’t need to implement it with a serializable interface. The reflection problem is also not there. Therefore, it is 100% guaranteed that only one instance of the singleton is present within a JVM. Thus, this method is recommended as the best method of making singletons in Java.

public enum SingletonEnum {
    INSTANCE;
    int value;
    public int getValue() {
        return value;
    }
    public void setValue(int value) {
        this.value = value;
    }
}
public class EnumDemo {
    public static void main(String[] args) {
        SingletonEnum singleton = SingletonEnum.INSTANCE;
        System.out.println(singleton.getValue());
        singleton.setValue(2);
        System.out.println(singleton.getValue());
    }
}

One thing to remember here is, when serializing an enum, field variables are not getting serialized. For example, if we serialize and deserialize the SingletonEnum class, we will lose the value of the int value field (Refer to the Oracle docs for more details about enum serialization).

Read on DZone about Java Singletons using Enums

Lasă un răspuns

Adresa ta de email nu va fi publicată. Câmpurile obligatorii sunt marcate cu *

Acest site folosește Akismet pentru a reduce spamul. Află cum sunt procesate datele comentariilor tale.