美文网首页
第3项 使用私有构造方法或者枚举来实现单例

第3项 使用私有构造方法或者枚举来实现单例

作者: Cocoonshu粽子 | 来源:发表于2018-12-26 22:39 被阅读9次

单例即为只初始化一次的类,我们可以一贯性的认为,单例代表系统唯一的系统组件,就像是window manager(窗口管理器)或者file system(文件系统)。

我们有两种方法实现单例。但是两种方法我们都需要在这个待实现的单例中提供一个私有的构造方法和一个共有静态的方法来处理这个唯一的实例。在其中的一个实现中,我么希望类的成员变量是final修饰的。

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

私有构造函数只调用一次,以初始化公共静态最终字段Elvis.INSTANCE。 缺乏公共或受保护的构造函数保证了“单一的”宇宙:一旦Elvis类被初始化,就会存在一个Elvisinstance - 不多也不少。 客户端所做的任何事情都无法改变这一点,但有一点需要注意:特权客户端可以借助AccessibleObject.setAccessible方法反射性地调用私有构造函数(第65项)。 如果您需要防御此攻击,请修改构造函数以使其在要求创建第二个实例时抛出异常。 在实现单例的第二种方法中,公共成员是一种静态工厂方法:

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

对Elvis.getInstance的所有调用都返回相同的对象引用,并且不会创建其他任何Elvis实例(前面提到过相同的警告)。
公共字段方法的主要优点是API清楚地表明该类是单例:公共静态字段是final,因此它将始终包含相同的对象引用。 第二个优点是它更简单。

静态工厂方法的一个优点是,它使您可以灵活地改变主意,关于类是否是单例而不更改其API。 工厂方法返回唯一的实例,但可以修改它,例如,为每个调用它的线程返回一个单独的实例。 第二个优点是,如果您的应用需要,您可以编写通用的单件工厂(第30项)。 使用静态工厂的最后一个优点是方法引用可以用作供应商,例如Elvis :: instance是Supplier <Elvis>。 除非其中一个优点相关,否则公共领域方法更可取。

要创建一个使用这些方法中的任何一种可序列化的单例类(第12章),仅仅将实现Serializable添加到其声明中是不够的。 要维护单例保证,请声明所有实例字段为瞬态并提供readResolve方法(第89项)。 否则,每次反序列化序列化实例时,都会创建一个新实例,在我们的示例中,将导致虚假的猫王目击。 要防止这种情况发生,请将此readResolvemethod添加到Elvis类:

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

这种方法类似于公共领域方法,但它更简洁,免费提供序列化机制,并提供了对多个实例化的铁定保证,即使面对复杂的序列化或反射攻击。 这种方法可能会有点不自然,但单元素枚举类型通常是实现单例的最佳方法。 请注意,如果您的单例必须扩展Enum以外的超类,则不能使用此方法(尽管您可以声明枚举来实现接口)。

相关文章

  • 第3项 使用私有构造方法或者枚举来实现单例

    单例即为只初始化一次的类,我们可以一贯性的认为,单例代表系统唯一的系统组件,就像是window manager(窗...

  • 用私有构造器或者枚举来强化Singleton属性

    第三条:用私有构造器或者枚举来强化Singleton(单例)属性 1. 用私有构造器来强化 很简单,就是将构造器声...

  • 单例模式

    单例模式的实现方式: 构造函数私有 通过静态方法或枚举返回对象 多线程环境下也要保证单例对象只有一个 单例对象在反...

  • java 相关的好文章分类

    1、枚举 1、充分利用枚举默认构造方法私有化的性质来实现单例。由于里面的成员变量都是final修饰的,因此不会有线...

  • 设计模式之单例

    单例模式 一般私有化构造函数 通过一个静态方法来获取唯一单例对象 两个例子 静态内部类单例模式 枚举模式 懒汉模式...

  • 读 effective java 中文版第二版读后感(第二天)

    第三条 用私有构造器或者枚举类型强化Singleton属性 1.第一种实现方法 通过私有构造器的方法实现: 弊端:...

  • Effective Java第三版速览

    创建与销毁对象 静态工厂方法取代构造方法 构建器取代多参数构造方法 强制单例使用私有构造方法或枚举类型 强制非实例...

  • java 枚举

    枚举 注意:枚举是单例的,单例要保证私有化构造器。 1. 如何自定义枚举类 提供类的属性,声明为 private ...

  • 枚举单例

    描述 本文先反编译枚举,再使用枚举实现单例 枚举 单例 单例源码 单例反编译 引用 http://www.benf...

  • 设计模式之:单例模式

    实现单例应该注意以下4点: 构造函数不对外开放,一般为private; 通过一个静态方法或者枚举返回单例类对象; ...

网友评论

      本文标题:第3项 使用私有构造方法或者枚举来实现单例

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