单例和静态类案例研究

时间:2011-12-19 03:03:22

标签: java singleton static-class

已经asked单例和静态类之间有什么区别。然而,知道差异,每次我需要选择时,我仍然感到困惑。

所以对于我自己,我定义了两种不同的情况 - 我主要是为POJO类(在java中)使用单例,如果只有这个类的一个实例(很少)和所有服务类的静态类(经常发生)。

例如,在我的应用程序中,我需要存储消息(我有一个可序列化的类Message),将它们写入文件,从文件中读取并在运行时访问。我没有看到任何理由在这里使用单例,静态类是可以的。唯一的静态类是MessageStorage,它有3个函数 - read,write和getMessages,还有一个静态的私有消息列表。

这种方法是否合理,如果不合理,它的问题是什么?

3 个答案:

答案 0 :(得分:1)

理想的设计: - )

  • MessageStore应该是一个接口
  • MessageStoreFactory应该是一个带有getMessageStore()方法的单例(如果getMessageStore()每次都返回相同的消息存储,这不是问题,并且你有你的单例)。
  • 您可以拥有多个MessageStore实现,例如FileMessageStore,JDBCMessageStore,SubversionMessageStore等......
  • 最重要的是,您可以使用MockMessageStore来模拟消息存储,并能够独立于消息存储测试依赖于消息存储的组件(并隔离任何故障)。例如,如果您正在测试MessageView并收到错误,那么您可以确定错误是在MessageView中而不是在静态MessageStore中,因为MockMessageStore是正确的。

这就是酷孩子们现在所做的事情,无论如何......依赖注入而不是工厂,但一次一步......

答案 1 :(得分:1)

这里真正理解的是c#/ java有不同的内存组。

所有类都将被加载到称为类加载器内存的内存区域中。如果你做了一些静态的东西,它仍然存在于类加载器内存中。它可以从那里使用,但只能有1个实例。类加载器内存没有垃圾收集器,一切都在应用程序的生命周期中保留。

创建类的实例(无论是否为单例)意味着完成内存复制,从类加载器内存复制类并将其复制到存储实例的区域。实例可以被垃圾收集。

单例和静态类的选项之间的实际决策点是:

1)你想要继承,还是你班级的接口(如果你想要单身人士) 2)强制你的类具有与你的应用程序相同的生命周期是有意义的(即你必须手动清除该类或编写一个方法来执行它,这通常会增加代码,从而降低可维护性)。 (如果没有那么你想要单身人士)
3)您的应用程序是否需要可扩展性和变更潜力。 Singleton现在通常被认为是反模式,IF通过静态属性实现。这样做的原因是你投资基础设施,比如在你的类上公开一个静态实例属性,这可能完全不是你想要的,因为你的单个窗口应用程序可能会突然变成多窗口,你需要重写代码。 (重写代码表明设计不好,特别是如果它的核心基础设施)。

作为一般经验法则,我建议如下:

  • 任何有类范围变量的类,应该是单例(因为需要将其扩展出来)。
  • 每个方法独立的任何类都应该是静态的。

答案 2 :(得分:1)

在Java中使用“singleton”的两个主要原因是:

1)因此,某些存储可以与其他“静态”类相关联。

2)对于给定服务的不同子类(或接口实现),您可能有多个“单例”,并且单例作为识别要使用的特定服务的方式传递。

当然,您可以使用“静态”类的静态字段来包含数据,而不是#1,但是通常更方便(并且在许多情况下,更高效)拥有主题类的单个实例包含数据,vs多个静态成员,它们是其他类的实例。

而且,#2,在单个类的JDK中有许多案例实际上是以定义“常量”为幌子实现多个“单例”。 (例如,java.awt.font.TextAttribute。)

一般来说,在Java中使用单例的动机比在基于C的语言中要少,因为Java确实实现了真正的类关联(和类保护)静态数据,而不是模糊地伪装(如果伪装)全局在C语言中使用的静态,因此可以在一个类中简单地拥有多个静态字段,而不需要有一个“中心”对象来包含C语言中的字段。