美文网首页
ITEM 3: 应当使用私有构造函数或枚举实现单例属性

ITEM 3: 应当使用私有构造函数或枚举实现单例属性

作者: rabbittttt | 来源:发表于2019-03-31 14:56 被阅读0次

ITEM 3: ENFORCE THE SINGLETON PROPERTY WITH A PRIVATE CONSTRUCTOR OR AN ENUM TYPE
单例是一种只能实例化一次的类。单例通常表示无状态对象,如函数或系统中的唯一组件。单例的类会使用户代码的测试其变得困难,因为除非它实现了作为其类型的接口,否则就不可能用模拟实现代替单例。
实现单例有两种常见的方法,它们都基于保持构造函数私有和导出公共静态成员来提供对惟一实例的访问。在一种方法中,成员是一个公共的、final的字段:

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

私有构造函数只被调用一次,用于初始化成员变量 INSTANCE。没有public / protected 构造函数,这样能保证全局仅存在一个Elvis 实例。但需要注意的是,特权用户可以在 AccessibleObject.setAccessible() 方法的帮助下通过反射调用私有构造函数。如果想填补这个漏洞,我们可以修改私有构造函数,当用户试图创建第二个实例时抛出异常。
第二种方法是利用一个静态工厂方法返回唯一实例:

// 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() 方法的调用都会返回同一个实例,不会创建其他新的实例(同样存在上一个方法的特权用户问题)。
公共字段方法的主要优点是,API明确表示该类是单例的:公共静态字段是final,因此它总是包含相同的对象引用;而且它更简单。
静态工厂方法的一个优点是,我们可以灵活地改变想法,不论类是否为单例,我们不需要改变API。工厂方法返回唯一的实例,但是可以修改为,例如返回调用它的每个线程的单独实例。第二个好处是,如果有需要,我们可以写一个泛型单例工厂。A final advantage of using a static factory is that a method reference can be used as a supplier, for example Elvis::instance is a Supplier<Elvis>. (???)。除非有以上这些好处,否则更推荐公共字段的方案。
如果需要使单例类可序列化,仅仅实现 Serializable 接口是不够的。为了维护单例保证,需要声明所有实例字段为transient,并提供一个readResolve方法。否则,每次反序列化发生时,都会创建一个新实例。以上面的类 Elvis 为例,会导致创建新的 Elvis 实例,为了防止出现这种情况,需要实现 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() { ... } 
}

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

相关文章

  • ITEM 3: 应当使用私有构造函数或枚举实现单例属性

    ITEM 3: ENFORCE THE SINGLETON PROPERTY WITH A PRIVATE CON...

  • 单例模式

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

  • Effective Java 2.0_中文版_Item 3

    文章作者:Tyan博客:noahsnail.com | CSDN | 简书 Item 3 用私有构造函数或枚举类型...

  • java 枚举

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

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

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

  • 强化Singleton属性

    法则:用私有构造器或枚举类型强化Singleton属性 实现Singleton的三种方法: 把构造器保持为私有的,...

  • 提示三

    今天看第三条:使用私有构造方法或枚类强化 Singleton 属性。 文章首先介绍了两种常见的实现单例的方法。第一...

  • Symbol

    例1 例2 例3(使用Symbol实现属性私有化)

  • kotlin实现单例

    java实现单例模式 一直习惯于java的写法,java实现单例主要的思想是构造函数私有,然后考虑线程安全,在实现...

  • 设计模式之单例

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

网友评论

      本文标题:ITEM 3: 应当使用私有构造函数或枚举实现单例属性

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