如何在Scala中对对象进行全局访问而不将其作为单例或将其传递给所有对象?

时间:2014-01-31 17:42:25

标签: scala singleton

我有一个Logger类,可以在我的应用程序中记录事件。虽然我在这个应用程序中只需要一个记录器实例,但我希望这个类可以重用,所以我不想让它成为单例并将它与我对该应用程序的特定需求结合起来。

我希望能够从应用程序的任何位置访问此Logger实例,而无需每次都创建一个新的实例或将其传递给可能需要记录某些内容的每个类。我目前所做的是有一个ApplicationUtils单例,我用它作为应用程序Logger的访问点:

object ApplicationUtils {
    lazy val log : Logger = new Logger()
}

然后我有一个Loggable特性,我将其添加到需要Logger的类中:

trait Loggable {
    protected[this] lazy val log = ApplicationUtils.log
}

这是我尝试完成的有效方法吗?感觉有点黑客。我可以使用更好的方法吗?我是Scala的新手。

2 个答案:

答案 0 :(得分:5)

object s中添加功能时要小心。该功能很容易测试,但如果你需要测试该代码的客户端以确保它们正确地与它进行交互(通过模拟和间谍),那么你就会陷入困境,导致对象编译成最终的类,因此无法模拟。

相反,请使用此模式:

trait T { /* code goes here */ }

object T extends T /* pass this to client code from main sources */

现在,您可以在测试代码中为trait T创建Mockito模拟/间谍,将其传递并确认测试代码与trait T代码的交互是应该的。< / p>

如果您的代码是T的客户并且与其的交互不需要测试,则可以直接引用object T

答案 1 :(得分:5)

要解决您尝试做的事情(而不是您要问的问题),请查看TypeSafe的scalalogging包。它提供了Logging特征,您可以这样使用:

class MyClass extends Logging {
  logger.debug("This is very convenient ;-)")
}

这是SLF4J的基于宏的包装器,因此logger.debug(...)之类的内容被编译为if (logger.isDebugEnabled) logger.debug(...)