单身模式

时间:2010-11-02 19:06:02

标签: java singleton

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

  1. 特权客户端可以借助AccessibleObject.setAccessible()方法反射性地调用私有构造函数。如果您需要对此进行辩护,请修改构造函数。
    究竟如何调用私有构造函数?什么是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. 单元素枚举类型是实现单例的最佳方式。
    为什么?怎么样?

5 个答案:

答案 0 :(得分:11)

  

特权的cleint可以借助AccessibleObject.setAccessible方法反射性地调用私有构造函数。如果需要保护它,请修改构造函数。我的问题是:如何调用私有构造函数?什么是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,否则将自动抛出。

  

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

这方面的例子在书中,正如理由一样。你不明白哪一部分?

答案 1 :(得分:2)

  

特权的cleint可以反射性地调用私有构造函数   借助于   AccessibleObject.setAccessible方法,   如果您需要为此辩护,请修改   构造函数。我的问题是:如何   私有构造函数是否完全可以   调用?是什么   AccessibleObject.setAccessible ??

您可以使用java反射来调用私有构造函数。

  

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

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

  

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

不确定你是什么意思?你的意思是克隆()或其他我不知道的东西?

  

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

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

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

答案 2 :(得分:2)

单身人士是一个很好的学习模式,特别是作为入门设计模式。但要注意,它们通常最终成为over-used patterns之一。有人认为它们是"anti-pattern"。最好的建议是"use them wisely."

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

答案 3 :(得分:1)

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

就您的问题而言,我认为 1 2 3 都可以通过说“使用{{1}”来回答} -singleton”。然后你不必担心构造函数accessiblity问题,enum等等。就 4 而言,上面对它们来说是一个很好的论据。我还要问,您是否阅读过有效Java中明确回答您问题的部分?

答案 4 :(得分:0)

示例singleton lazy init: 班主:

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);
    }
}

班级单身人士:

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