Daily Archives: September 29, 2020

Singleton

Singleton with public final field

Problem of this is that this can create another instance by reflection. The fix is that in private method, add a INSTANCE check.

public class SingletonWithPublicFinalField {

    public static final SingletonWithPublicFinalField INSTANCE = new SingletonWithPublicFinalField();

    private SingletonWithPublicFinalField() {
//        if (INSTANCE != null) {
//            throw new RuntimeException("Singleton instance already existed");
//        }
    }

    public static void main(String[] args) throws Exception{
        SingletonWithPublicFinalField instance1 = SingletonWithPublicFinalField.INSTANCE;
        System.out.println(instance1);

        Constructor.setAccessible(SingletonWithPublicFinalField.class.getConstructors(), true);
        Object instance2 = Class.forName(SingletonWithPublicFinalField.class.getName()).newInstance();
        System.out.println(instance2);
    }

}

Singleton with public static factory method. Good of it is that it is very like a class. It is easy to convert it into a normal non-singleton class. Just rewrite getInstance() method.

public class SingletonWithPublicStaticFactoryMethod {

    public static final SingletonWithPublicStaticFactoryMethod INSTANCE = new SingletonWithPublicStaticFactoryMethod();

    private SingletonWithPublicStaticFactoryMethod() {}

    public static SingletonWithPublicStaticFactoryMethod getInstance() {
        return INSTANCE;
    }

    public static void main(String[] args) throws Exception{
        SingletonWithPublicStaticFactoryMethod instance = SingletonWithPublicStaticFactoryMethod.getInstance();
        System.out.println(instance);
    }

}

Singleton serializable issue. When deserializing, it creates a different instance. The fix is to override readResolve() method and return the INSTANCE.

public class SingletonWithSerializable implements Serializable {

    public static final SingletonWithSerializable INSTANCE = new SingletonWithSerializable();

    private SingletonWithSerializable() {}

    public static SingletonWithSerializable getInstance() {
        return INSTANCE;
    }

    // When deserializing, it returns a different instance. The fix is to add below
//    private Object readRsolve() {
//        return INSTANCE;
//    }

    public static void main(String[] args) throws Exception{
        SingletonWithSerializable instance = SingletonWithSerializable.getInstance();
        System.out.println(instance);

        try (ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("file1.ser"))) {
            out.writeObject(instance);
        }

        try (ObjectInputStream in = new ObjectInputStream(new FileInputStream("file1.ser"))) {
            SingletonWithSerializable readObject = (SingletonWithSerializable) in.readObject();
            System.out.println(readObject);
        }
    }

}

The best option is to use enum singleton. It avoids reflection hacking or serializing issue very easily.

public enum  SingletonWithEnum {
    INSTANCE;

    public void doSomeMethod() {
        System.out.println("some method");
    }

    public static void main(String[] args) throws Exception {
        SingletonWithEnum singletonWithEnum = SingletonWithEnum.INSTANCE;
        SingletonWithEnum instance = SingletonWithEnum.INSTANCE;
        System.out.println(instance);

        try (ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("file1.ser"))) {
            out.writeObject(instance);
        }

        try (ObjectInputStream in = new ObjectInputStream(new FileInputStream("file1.ser"))) {
            SingletonWithEnum readObject = (SingletonWithEnum) in.readObject();
            System.out.println(readObject);
        }

        instance.doSomeMethod();
    }
    
}

 

Anti Pattern – Javabean Pattern

Call a non-argument constructor, then call a series of set method. Avoid using it.

class Person {
    String firstName;
    String lastName;
    int age;
    
    public Person() {}

    public String getFirstName() {
        return this.firstName;
    }
    
    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }
    
    public String getLastName() {
        return this.lastName;
    }
    
    public void setLastName(String lastName) {
        this.lastName = lastName;
    }
    
    public int getAge() {
        return this.age;
    }
    
    public void setAge(int age) {
        this.age = age;
    }

}

Anti Pattern: Telescoping constructor pattern

It lists all constructors. This is an anti pattern. Avoid using it.

class Person {
    String firstName;
    String lastName;
    int age;
    public Person() {}

    public Person(String firstName) {
        this.firstName = firstName;
    }

    public Person(String firstName, String lastName) {
        this.firstName = firstName;
        this.lastName = lastName;
    }

    public Person(String firstName, String lastName, int age) {
        this.firstName = firstName;
        this.lastName = lastName;
        this.age = age;
    }

}

 

static factory pattern

static factory method over constructors:
1. Constructor don’t have meaningful names, but static factory method has
2. Static factory method returns same type, subtype, primitives
3. Static factory could return same instance if needed

Sample of static factory method:

String value1 = String.valueOf(1);
String value2 = String.valueOf(1.0L);
Optional<String> value1 = Optional.empty();
Arrays.asList(1, 2, 3);

link