共享单例实例

3

我正在实现一个程序,它使用具有单例行为的共享实用程序类。

在主线程中创建了一个实用程序类的实例,并传递给所有其他实例化的对象:

SomeUtil util = new SomeUtil();

...

Foo foo = new Foo(util, arg1, arg2)
Bar bar = new Bar(util, arg3, arg4, arg5) 

有没有更优雅的方式来实现它(例如,设计模式)?


你已经给出了答案,使用单例模式。 - Illuminati
5个回答

5
正如其他人所提到的,单例模式可以是一种替代方案。但请注意,您当前的设计易于进行单元测试(因为您正在注入SomeUtil依赖项,因此在单元测试期间可以轻松地用模拟对象替换它),而单例模式使单元测试变得困难和棘手:
  • 它使您的对象依赖于全局状态,因此更难正确设置测试,并容易犯错误(例如忘记为特定测试正确初始化单例),
  • 由于您无法轻松识别给定代码是否依赖于全局状态,除非实际阅读整个代码,因此更难理解代码。
话虽如此,如果它是一个真正的实用程序类,即它没有内部状态,并且不依赖于任何使单元测试变得困难的东西(如DB或文件系统),那么将其用作单例可能是可以接受的(尽管这引发了一个问题:为什么您需要实例化它 - 通常实用程序类只有静态方法和私有构造函数以防止实例化)。

是的,实用类应该是无状态的,因此可以作为真正的单例或静态类来实现。 - Theodor

4
为什么要传递实用对象?SomeUtil 可以有静态方法,这样 Foo 和 Bar 中的方法就可以使用它。
此外,您还可以实现一个真正的单例模式。

1
+1. 实用类应该尽量是静态的,并且隐含的契约是无状态的(即线程安全)。 - pap
@pap:无状态意味着线程安全,但它们并不是完全相同的概念。您可以使用有状态对象实现线程安全。 - Mark Peters
@Mark:当然可以,我并没有意味着其他。我强调了无状态的线程安全性质,因为它是实用类的主要关注点。在我之前的评论中,用"and thusly"代替"ie"可以增加清晰度:) - pap

3

嗯,您可以使用单例模式,该模式通常在类本身中存储对单个实例的静态引用。

public class SomeUtil {
    private static final SomeUtil instance = new SomeUtil();
    public static SomeUtil getInstance() { 
        return instance;
    }
    //...
}

然而,这样做可能会使事情难以进行单元测试,所以请注意。通常,破坏注入的依赖关系比全局依赖关系容易得多。


SomeUtil类已按照您的描述实现,但从未完全作为单例利用。 - Theodor

1
为什么不直接使用一个真正的单例?这比到处传递单个实例要好得多。

1

解决这个问题最好的方法可能是添加/使用一些依赖注入框架。

  • 框架将会保证对象确实是单例(传统上,特别是在懒惰模式下进行时,这有点棘手)。
  • 您可以在测试时替换/控制单例“实例”。
  • 如果您想要的话,您可以摆脱作为构造函数参数传递的单例。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接