如何以适当的方式编写单身人士?

Som*_*Som 24 java singleton multithreading design-patterns

今天在我的采访中,一位采访者让我写了一个Singleton课程.我给出了答案

public class Singleton {

    private static Singleton ref;

    private Singleton() {
    }

    public static Singleton getInstance() {
        if (ref == null) {
            ref = new Singleton();
        }
        return ref;
    }
}
Run Code Online (Sandbox Code Playgroud)

突然他告诉我这是写作课的老方法.任何人都可以帮助我,为什么他这样说.

Roh*_*ain 43

在创建单例时,我首先想到的是enum.我通常使用枚举来实现单例:

enum Singleton {
    INSTANCE;
}
Run Code Online (Sandbox Code Playgroud)

使用枚举获得的一个好处是使用序列化.

随着单例类,你就必须确保序列化和反序列化不通过实现创建一个新的实例readResolve()方法,而这不符合枚举的情况.

使用类,您应该像这样创建单例:

public final class Singleton implements Serializable {
    // For lazy-laoding (if only you want)
    private static class SingletonHolder {
        private static final Singleton INSTANCE = new Singleton();
    }

    private Singleton() {
        if (SingletonHolder.INSTANCE != null) {
            // throw Some Exception
        }
    }

    public static Singleton getInstance() {
        return SingletonHolder.INSTANCE;
    }

    // To avoid deserialization create new instance
    @SuppressWarnings("unused")
    private Singleton readResolve() {
        return SingletonHolder.INSTANCE;
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 由于私有构造函数,无论如何,单例类可能不是子类.但宣称它是"最终的"让那些不警惕的程序员更加明显:-) (6认同)
  • @ user2775766.这不是硬性和快速的规则,但我建议将其作为最终,并尽量避免继承单身. (2认同)

Gle*_*est 14

最新标准方案:

先前的建议(来自'Effective Java 2'):

  • 使用枚举,具有单个伪计数常量,例如INSTANCE.数据字段和方法可以是静态的或非静态的(实例) - 两者的行为相同,因为只有一个实例

  • 好处:

    • 是的,这是一个单身人士.不可能通过任何机制创建多个实例(在任何JVM上的任何给定类加载器内).
    • 单例初始化是线程安全的.
  • 缺点(与上述标准解决方案相比):

    • 这个定义有点迟钝 - 'enum'外壳可能会误导缺乏经验的代码维护者.这是一个小小的黑客,而不是枚举的初衷.
    • 实现通过抽象泄漏.它违反了 统一访问原则
      • 它不能通过注入工作 - 客户端必须知道它是针对精确枚举实例的单例和代码
      • 客户端必须使用Singleton.INSTANCE.someMethod()
      • 客户端不能(简单地)对接口进行编码
      • 受到设计影响的客户端在单例与/从多实例对象之间发生变化
    • 扩展祖先类(Enum),防止从其他类继承
    • 序列化和反序列化只是在没有状态的情况下传递枚举常量名称 - 这在技术上确保只有一个实例,但对数据有空操作.在(罕见)事件中,想要在JVM /类加载器之间共享/同步单例状态,不能使用通过序列化进行的复制.


Pet*_*rey 10

你可以做

public enum Singleton {
    INSTANCE;
}
Run Code Online (Sandbox Code Playgroud)

对于没有实例的实用程序类

public enum Utility {
     ;

     public static void method();
}
Run Code Online (Sandbox Code Playgroud)

  • 没有实例的枚举 - 不会想到这一点.尼斯:-) (3认同)

spl*_*bob 8

正如其他人已经指出的那样,现在人们普遍认为枚举模式是单身人士与老派方法的更好方法,但我只想指出一个缺点.

我们有一个Singleton形式:

public enum Foo {
    INSTANCE;
}
Run Code Online (Sandbox Code Playgroud)

已经存在了一段时间,工作得很好.然后在代码审查期间,我们看到了:

public enum Foo {
    INSTANCE,
    ANOTHER;
}
Run Code Online (Sandbox Code Playgroud)

在我们用湿鲭鱼击打他的脸之后,有问题的编码器看到了他的方式的错误,并且必须退出和/或重写大量的代码.是的,我们在它投入生产之前就把它抓住了,但是必须做好工作来消除它.

我觉得这种类型的单身人士的弱点(尽管很小,也许很少见)与老派的方式相比.是的,你可以通过错误地实现它来打破任何模式,但是对于编码人员来说,打破一个辛格尔顿的枚举似乎比一个格式良好的老派单身人士要容易得多.

编辑:

为了完整起见,这里是一个enum Singleton,可以防止以后添加的其他值:

public enum Foo
{
  INSTANCE;
  // adding another type here will cause a runtime

  static
  {
    if (Foo.values().length != 1)
    {
      throw new IllegalStateException("Not a Singleton.");
    }
  }
}
Run Code Online (Sandbox Code Playgroud)