单身模式

像我之前的问题一样,这个问题引用了Effective Java 。 这次我有很多子问题。

  1. 特权客户端可以借助AccessibleObject.setAccessible()方法reflection性地调用私有构造函数。 如果您需要防范此操作,请修改构造函数。
    究竟如何调用私有构造函数? 什么是AccessibleObject.setAccessible()

  2. 您的专家对单身人士采用什么方法?

     // Approach A public class Test{ public static final Test TestInstance = new Test(); private Test(){ ... } . . . } // Approach B public class Test{ private static final Test TestInstance = new Test(); private Test(){ ... } public static Test getInstance() { return TestInstance; } . . . } 

    第二种方法不是更灵活,以防我们每次都要检查新实例或每次检查同一个实例吗?

  3. 如果我尝试克隆类/对象怎么办?

  4. 单元素枚举类型是实现单例的最佳方式。
    为什么? 怎么样?

特权锁定可以借助AccessibleObject.setAccessible方法reflection性地调用私有构造函数。如果需要保护它,请修改构造函数。 我的问题是:如何调用私有构造函数? 什么是AccessibleObject.setAccessible?

显然,类本身可以调用私有构造函数(例如,从静态工厂方法)。 反过来说,布洛赫正在谈论的是:

 import java.lang.reflect.Constructor; public class PrivateInvoker { public static void main(String[] args) throws Exception{ //compile error // Private p = new Private(); //works fine Constructor con = Private.class.getDeclaredConstructors()[0]; con.setAccessible(true); Private p = (Private) con.newInstance(); } } class Private { private Private() { System.out.println("Hello!"); } } 

2.专家对单身人士采取什么方法:

通常,第一个是受欢迎的。 第二个(假设您在返回新实例之前测试TestInstance是否为null)以需要同步或线程不安全为代价获得延迟加载。

当你的第二个例子没有在声明时将实例分配给TestInstance时,我写了上面的内容。 如上所述,上述考虑无关紧要。

第二种方法是不是更灵活,以防我们每次都要检查新实例或每次都是同一个实例?

这不是关于灵活性,而是关于何时产生创建一个(且唯一的)实例的成本。 如果你选择a)它是在课堂加载时产生的。 这通常很好,因为只有在需要时才会加载类。

当你的第二个例子没有在声明时将实例分配给TestInstance时,我写了上面的内容。 如前所述,在两种情况下,Singleton都将在类加载时创建。

如果我尝试克隆类/对象怎么办?

单身人士不应该出于明显的原因而允许克隆。 应抛出CloneNotSupportedException,除非由于某种原因实现Cloneable否则将自动抛出。

单元素枚举类型是实现单例的最佳方式。 为什么? 如何?

这方面的例子在书中,正如理由一样。 你不懂什么部分?

单身人士是一个很好的学习模式,特别是作为入门设计模式。 但要注意,它们通常最终成为最常用的模式之一 。 有人认为它们是一种“反模式” 。 最好的建议是“明智地使用它们”。

有关这个以及许多其他有用模式的详细介绍(我个人认为策略,观察者和命令比Singleton更有用),请查看Head First Design Patterns 。

特权锁定可以借助AccessibleObject.setAccessible方法reflection性地调用私有构造函数。如果需要保护它,请修改构造函数。 我的问题是:如何调用私有构造函数? 什么是AccessibleObject.setAccessible?

您可以使用javareflection来调用私有构造函数。

您的专家对单身人士采用什么方法:

我是使用枚举来实际执行此操作的粉丝。 这也在书中。 如果这不是一个选项,那么选择a更简单,因为您不必检查或担心已经创建了实例。

如果我尝试克隆类/对象怎么办?

不明白你的意思? 你的意思是克隆()或其他我不知道的东西?

单元素枚举类型是实现单例的最佳方式。 为什么? 如何?

啊,我自己的答案。 哈哈。 这是最好的方法,因为在这种情况下,java编程语言保证单例而不是开发人员必须检查单例。 这几乎就像单身人士是框架/语言的一部分。

编辑:我之前没有看到它是一个吸气剂。 更新我对此的回答 – 最好使用getInstance这样的函数,因为你可以控制通过getter发生的事情,但如果每个人都直接使用引用,你就不能这样做。 想想未来。 如果你最终做了SomeClass.INTANCE,然后你想让它变得懒惰,所以它不会立即加载,那么你需要在它被使用的任何地方进行更改。

Singleton(反)模式的第一条规则是不使用它 。 第二个规则是不要使用它 ,以便更容易获得您希望多个其他对象共享的类的单个实例, 特别是如果它是这些类的依赖项。 改为使用dependency injection。 Singletons有一些有效的用途,但是人们会严重滥用它们,因为它们很容易使用。 他们很难测试依赖于它们的类并使系统不灵活。

至于你的问题,我认为1,23都可以通过说“使用enum -singleton”来回答。 然后你不必担心构造函数accessiblity问题, clone() ing等。至于4 ,上面的内容对他们来说是一个很好的论据。 我还要问一下,您是否阅读过有效Java中明确回答您问题的部分?

示例singleton lazy init:类main:

 public class Main { public static void main(String[] args) { System.out.println(Singleton.getInstance("first").value); System.out.println(Singleton.getInstance("second").value); System.out.println(Singleton.getInstance("therd").value); } } 

class级单身人士:

 public class Singleton { private static Singleton instance; public String value; private Singleton (String s){ this.value =s; } public static Singleton getInstance(String param) { if (instance == null) instance = new Singleton(param); return instance; } } 

启动应用程序时,控制台将包含下一个字符串

 first first first 

\ | / 73