【问题标题】:Generalized Singleton base class in JavaJava中的广义单例基类
【发布时间】:2009-05-27 15:43:43
【问题描述】:

在 C++ 中,我知道可以使用模板创建单例基类。它在 Andrei Alexandrescu 的《现代 C++ 设计》一书中进行了描述。

这样的事情可以用Java实现吗?

【问题讨论】:

  • 您为什么要这样做? Singleton 基本上是一种反模式,你知道吗?
  • 一个原因可能是他想知道如何实例化一个未知类的实例。换句话说,给定类作为参数,请执行以下操作: Object instance = clazz instanceof Singleton ? (单例) clazz.getInstance() : new clazz(); (这当然需要一个可用的无参数构造函数,但这是一个不同的问题)。
  • @Elvian:就像所有事情一样,Singleton 在好的时候是好的,而不是在不好的时候。成为一名优秀程序员的一部分是知道何时以及何时不应用模式以及如果问题不适合现有的解决方案。换句话说,不知道何时正确应用它不是Singleton的错。
  • 简短的回答可能是肯定的,但我需要更多关于您正在寻找的内容的详细信息。
  • @Welbog:我同意有时您有充分的理由使用非常本地化的单例(即使在不使用某些控制反转机制的情况下无法对代码进行单元测试),但是“通用单例”对我来说似乎是一个疯狂的想法。为什么不将整个对象及其属性设为公开。更简单,相同的效果(几乎;))

标签: java design-patterns generics templates singleton


【解决方案1】:

我还没有在 Java 中看到一个令人满意的解决方案。有很多使用 C++ 中的模板或 .NET 中的泛型的示例,但是 Java 的泛型实现对静态成员有一些限制,这使得这很困难。

我见过的最佳选择是使用静态 HashMap 和工厂类。这使您可以创建一个可以为任何类的多个 Singleton 提供服务的工厂。

有关实现,请参阅this post

【讨论】:

  • (或其他):“这篇文章”不再是最新的。我真的需要那个链接。 :-/
【解决方案2】:

因为 Java 的泛型没有具体化,所以不可能以相同的方式实现泛化的 Singleton。因为泛型类型是从编译代码中“删除”的,所以必须在运行时显式初始化单例。

结果是,单例模板在 Java 中不会提供太多价值。

【讨论】:

  • 即使泛型被具体化,如果不对语言进行其他修改,它仍然无法工作。例如,静态变量仍将由同一类的所有参数化共享。
  • 通过具体化的泛型,我可以设想一个反映实际类型的实现来查找类成员变量。我可能会推测,但我想我应该在元推测中划清界限。
【解决方案3】:

是的,但所有方法都有其缺陷。它们要么很昂贵(使用synchronized),要么无法进行测试(final static)。

见右侧链接:

“最先进的技术”是使用容器或工厂根据需要创建单例并将它们保存在某种缓存中。参见 Spring、Guice 等。

【讨论】:

    【解决方案4】:

    在 1997 年,我尝试使用 JDK 1.0.2 执行此操作,并得出结论,无法创建可继承的单例。据我所知,Java 还没有获得任何允许这样做的新功能。

    但是,手动执行此操作并不涉及大量样板代码,每个类可能需要 10 行左右。如果您需要创建某种匿名工厂机制,单例可以为实例化协议实现一个带有占位符的接口。

    【讨论】:

    • 一个好的单例是三行代码。类声明、实例声明和初始化器,以及私有构造函数。
    【解决方案5】:

    您可以使用静态 HashMap(或用于线程安全的 Hashtable)来存储不同模板的所有实例,如 @reed-copsey 所述。 单例类示例:

    public class Singleton<T extends Parent> {
        private static HashMap<Class, Singleton> instanceMap = new HashMap<Class, Singleton>();
    
        private Singleton() {
    
        }
    
        public static <T> Singleton getInstance(Class<T> tClass) {
            if (!instanceMap.containsKey(tClass))
                instanceMap.put(tClass, new Singleton());
            return instanceMap.get(tClass);
        }
    
    }
    

    您可以将此单例用作:

    public static void main(String[] args) {
        Singleton instance1 = Singleton.getInstance(Child1.class);
        Singleton instance2 = Singleton.getInstance(Child1.class);
        assert instance1 == instance2;
    
        Singleton instance3 = Singleton.getInstance(Child2.class);
        assert instance1 != instance3;
    }
    

    单例类会针对不同的类类型返回不同的实例。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-02-18
      • 2023-03-20
      • 1970-01-01
      • 2017-02-13
      • 1970-01-01
      • 1970-01-01
      • 2023-03-11
      相关资源
      最近更新 更多