2

已经有人问过单例类和静态类有什么区别。但是,知道了区别,每次需要选择的时候我还是会感到困惑。

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

例如,在我的应用程序中,我需要存储消息(我有一个可序列化的类 Message),将它们写入文件,从文件中读取并在运行时访问。我看不出有什么理由在这里使用单例,静态类就可以了。唯一的静态类是 MessageStorage,它具有 3 个功能 - 读取、写入和 getMessages 以及一个静态私有消息数组列表。

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

4

3 回答 3

1

理想的设计:-)

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

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

于 2011-12-19T03:39:30.100 回答
1

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

您的所有类都将加载到称为类加载器内存的内存部分中。如果您制作的东西是静态的,它会保留在类加载器内存中。它可以从那里使用,但只能有 1 个实例。类加载器内存没有垃圾收集器,在应用程序的整个生命周期内,所有内容都保留在那里。

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

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

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

作为一般的经验法则,我会推荐以下内容:

  • 任何有类范围变量的类,都应该是一个单例(因为需要潜在地扩展它)。
  • 每个方法独立存在的任何类都应该是静态的。
于 2011-12-19T03:39:31.783 回答
1

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

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

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

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

而且,关于 #2,在 JDK 中有许多情况下,一个类实际上以定义“常量”的名义实现了多个“单例”。(例如,java.awt.font.TextAttribute。)

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

于 2011-12-19T03:43:28.510 回答