美文网首页Effective Java 第三版
条目3:通过私有构造方法或者枚举创建单例

条目3:通过私有构造方法或者枚举创建单例

作者: lmtoo | 来源:发表于2018-02-12 17:51 被阅读0次

    由于无法模拟替换单例,使测试更加困难,除非单例实现了自己的接口。

    有两种比较常见的方式来实现单例:都是通过私有构造器和暴露静态成员来访问实例的方式

    第一种:final的静态成员变量

    public class Elvis {

            public static final Elvis INSTANCE = new Elvis();

            private Elvis() { ... }

            public void leaveTheBuilding() { ... }

    }

    初始化静态成员变量INSTANCE 时只调用私有构造函数一次。

    但是通过反射并且设置AccessibleObject.setAccessible可以创建多个实例。

    如果不允许这样做可以在构造函数中做判断并抛出异常。

    优点:

    由于final类型的成员变量,所以它只会总是包含同一个对象的引用,并且很简单

    第二种:提供静态工厂方法

    // 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() { ... }

    }

    此方法也有同样的缺点:通过反射并且设置AccessibleObject.setAccessible可以创建多个实例。

    优点:

    可灵活的返回任何对象,而不用改变API;同时这个方式可以确保单个线程范围的单例

    可以编写泛型的单例工厂

    静态工厂可以作为一个Supplier:

    Elvis::instance 是一个 Supplier<Elvis>

    防止通过反序列化产生多个对象

    对于可序列化的单例对象,可以设置实例字段为transient,并且提供readResolve方法

    // 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;

    }

    第三种:单元素的枚举

    // Enum singleton - the preferred approach

    public enum Elvis {

        INSTANCE;

        public void leaveTheBuilding() { ... }

    }

    单元素的枚举是实现单例的最佳方式

    相关文章

      网友评论

        本文标题:条目3:通过私有构造方法或者枚举创建单例

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