实现Singleton模式

时间:2011-02-07 22:31:22

标签: java design-patterns singleton

如果我们将一个类实现为单例,我们将执行以下操作

class Single
{
  private Single singleton;

  public static Single getInstance()
  {
    if(null == singleton)
    {
      singleton = new Single();
    }
    return singleton;
  }

  //then we make the constructor private
  private Single()
  {
  }
}

考虑到上述情况,覆盖clone()以及防止类的多个实例是一个好主意吗?

5 个答案:

答案 0 :(得分:5)

clone()界面中没有Cloneable方法。如@Ivan points out所示,如果您的班级没有实施Cloneable,那么calling Single#clone() will throw a CloneNotSupportedException


也就是说,克隆是目前编写良好的Java中不常发生的事情。正如Josh Bloch在 Effective Java 中所写,第11项:

  

Cloneable接口用作对象的 mixin接口(第18项)   宣传他们允许克隆。不幸的是,它没有达到这个目的。它的   主要缺陷是缺少clone方法,Object的克隆方法受到保护。   如果不诉诸反思(第53项),你就不能调用clone   对象上的方法仅仅因为它实现了Cloneable。即使是反光的   调用可能会失败,因为无法保证对象具有可访问性   clone方法。尽管有这个缺陷和其他设施,该设施已广泛使用,因此它付出了代价   理解它。

...基本上,人们不会/不应该使用clone()。这是一个设计糟糕的界面,如果你想让你的对象可以克隆,最好提供一个复制构造函数或复制工厂方法(代码从第11项中窃取):

public Yum(Yum yum); // copy constructor
public static Yum newInstance(Yum yum); // copy factory

当我谈论 Effective Java 时,有一种更好的方法来编写单例,假设你确实需要一个(这是一个很大的if! )。

  

从1.5版开始,实现单例的第三种方法。只是   使用一个元素创建一个枚举类型:

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

除了它之外,这种方法在功能上等同于公共领域方法 更简洁,免费提供序列化机制,并提供 铁定的保证反对多重实例化,即使面对复杂 序列化或反射攻击。虽然这种方法尚未广泛应用 采用,单元素枚举类型是实现单例的最佳方式。

答案 1 :(得分:2)

如果您不实现cloneable,则它不应该是可复制的。 附: 一个更干净的java单曲是:

class Single { 
 private static final Single singleton = new Single();
 private Single() { }

 public static Single getInstance() {
  return single;
 }
}

答案 2 :(得分:2)

单个对象上对clone()的任何调用都将失败,如下所述:

http://download.oracle.com/javase/1.4.2/docs/api/java/lang/Object.html#clone%28%29

如果该课程不是Cloneable(未指定implements Cloneable),则会引发CloneNotSupportedException错误。

所以不,没有必要。并且代码较少:)

答案 3 :(得分:0)

默认情况下,clone()方法被标记为受保护,但如果您的类扩展了另一个支持克隆的类,则可能违反单例的设计原则。

在这种情况下,是的,这是一个好主意:

 public Object clone()
    throws CloneNotSupportedException
  {
    throw new CloneNotSupportedException(); 
  }

答案 4 :(得分:0)

正如he所说,没有什么可以覆盖的 关于你的单例实现 - 一般来说有很多很多缺陷(除了代码示例中明显的错误)。考虑多线程,反射,序列化/反序列化。将它作为带有1个常量的枚举将更容易,因为您不必编写任何代码来强制执行该属性。

查看this对另一个问题的回答(忽略关于hashCode()的部分)。另请注意评论。