鸡爪读Effective Java记录3:用私有构造器或者枚举类型强化Singleton属性

用私有构造器或者枚举类型强化Singleton属性

what?

Singleton
指就被实例化一次的类,也就是我们常听到单例模式。Singleton通常被用来代表一个无状态的对象

do?

实现Singleton有两种常见的方法。这两种方法都要保持构造器为私有的,并导出公有的静态成员,以便允许客户端能够访问该类的唯一实例。

one

使用公有的final域静态成员

public class Elvis {
    public static final Elvis INSTANCE = new Elvis();

    private Elvis() { }

    public void leaveTheBuilding() {
        System.out.println("鸡你太美");
    }

    public static void main(String[] args) {
        Elvis elvis = Elvis.INSTANCE;
        elvis.leaveTheBuilding();
    }
}

仅有的构造器是私有的,客户端不能通过构造器创建Elvis,这样子私有构造器仅被调用一次,就是程序加载Elvis类是实例化公有的静态的final域的INSTANCE的时候被调用。这样子保证了E1vis的全局唯-性:一旦E1vis类被实例化,将只会存在一个EIvis实例。

但是要提醒一点:享有特权的客户端可以借助Accessibleobjeet.setAecessible方法通过反射机制调用私有构造器。如果需要防止这种情况,我们可以修改构造器让它在被要求创建第二个实例的时候抛出异常。

public class Elvis {
    public static final Elvis INSTANCE = new Elvis();

    private Elvis() { 
        throw new AssertionError("小黑子,哥哥下蛋给你吃");
    }

    public void leaveTheBuilding() {
        System.out.println("鸡你太美");
    }

    public static void main(String[] args) {
        Elvis elvis = Elvis.INSTANCE;
        elvis.leaveTheBuilding();
    }
}

two

提供一个公有方法:静态工厂方法

public class Elvis {
    private static final Elvis INSTANCE = new Elvis();
    private Elvis() { }
    public static Elvis getInstance() { return INSTANCE; }

    public void leaveTheBuilding() {
        System.out.println("有时间学点唱、跳、rap");
    }

    public static void main(String[] args) {
        Elvis elvis = Elvis.getInstance();
        elvis.leaveTheBuilding();
    }
}

使用公有方法可以更加灵活,我们可以再自定义一些操作

other

上面的两种方式,如果我们要实现可序列化,单纯 implements Serializable 是不够,我们每次反序列化后都是获得一个新实例

鸡爪读Effective Java记录3:用私有构造器或者枚举类型强化Singleton属性_第1张图片

为了维护并保证Singleton,我们在Elvis中添加readResolve方法,当我们通过反序列化readObject()方法获取对象时会去寻找readResolve()方法,如果该方法不存在则直接返回新对象,如果该方法存在则按该方法的内容返回对像。这个的细节以后再来填。

private Object readResolve(){
    return INSTANCE;
}
鸡爪读Effective Java记录3:用私有构造器或者枚举类型强化Singleton属性_第2张图片

当然还有个更好的模式,就是我们学习单例模式常看到的枚举

public enum Elvis {
    INSTANCE;

    public void leaveTheBuilding() {
        System.out.println("只因鸡你太美");
    }

    public static void main(String[] args) {
        Elvis elvis = Elvis.INSTANCE;
        elvis.leaveTheBuilding();
    }
}

枚举类型编写起来会更加简洁,同时也无偿提供序列化机制,绝对防止多次实例化不同问题,也可以防止反射攻击。

如果Singleton不必须扩展一个超类,单元素的枚举类型往往是实现Singleton的最佳方法。

end

单例模式当然还有更加优化的方案,这里就立足于书本来讨论记录。序列化的细节以后来填。

你可能感兴趣的:(Effective,Java,单例模式,java,开发语言)