提示三

作者: 飞絮搅青冥 | 来源:发表于2022-04-02 22:57 被阅读0次

    今天看第三条:使用私有构造方法或枚类强化 Singleton 属性。

    文章首先介绍了两种常见的实现单例的方法。第一种是用final修饰的常量。

    // Singleton with public final field
    public class Elvis {
        public static final Elvis INSTANCE = new Elvis();
        private Elvis() { ... }
        public void leaveTheBuilding() { ... }
    }
    

    这样因为构造器是私有的,所以别人无法在创建出对应的实例。接着作者提醒采用反射的方法还是可以调用私有方法构造出实例,所以还要在构造器中加以判断来以防万一。这一点我是没有想到的,虽然平时自己也写过反射,但是在这种时候就联想不到反射可能带来的危害,以后需要更加重视反射。

    接着第二种方法是用一个静态的工厂来实现单例。

    // Singleton with static factory
    public class Elvis {
        private static final Elvis INSTANCE = new Elvis();
        private Elvis() { ... }
        public static Elvis getInstance() { return INSTANCE; }
        public void leaveTheBuilding() { ... }
    }
    

    同样是私有的构造器,这次连实例对象也是私有的了,都靠getInstance的静态方法来实现细节。它相比前一种方法就更灵活,在不改变API的前提下,就可以改变该类是否单例的实现。其次它可以通过方法引用(method reference)作为提供者,例如 Elvis::instance 等同于 Supplier<Elvis> 。

    最后作者还介绍了java1.5以后支持的用单例来实现singleton的方法。

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

    这种方式类似于公共属性方法,但更简洁,无偿地提供了序列化机制,并提供了防止多个实例化的坚固保证,即使是在复杂的序列化或反射攻击的情况下。这种方法可能感觉有点不自然,但是单一元素枚举类通常是实现单例的最佳方式。但是如果单例必须继承 Enum 以外的父类(尽管可以声明一个Enum 来实现接口),那么就不能使用这种方法。

    想想我们系统中的单例,一般常见的都是通过 getInstance 方法来获取的,好像很少看到通过单一元素枚举来实现的,确实这样做需要新建一个枚举类,可能更为麻烦,有机会自己可以实现一个这样的单例来比较一下。

    相关文章

      网友评论

          本文标题:提示三

          本文链接:https://www.haomeiwen.com/subject/dwmxsrtx.html