Seb*_*iot 21 logging singleton scala
我已经看过在Scala中登录的示例,它通常看起来像这样:
import org.slf4j.LoggerFactory
trait Loggable {
private lazy val logger = LoggerFactory.getLogger(getClass)
protected def debug(msg: => AnyRef, t: => Throwable = null): Unit =
{...}
}
Run Code Online (Sandbox Code Playgroud)
这似乎与具体的日志框架无关.虽然这样做了,但它还在每个想要进行日志记录的实例中引入了一个无关的lazy val ,这可能是整个应用程序的每个实例.这对我来说似乎太沉重了,特别是如果你有一些特定类型的"小实例".
有没有办法将记录器放在具体类的对象中,只需使用继承?如果我必须在类的对象中显式声明记录器,并从类/特性显式地引用它,那么我编写的代码几乎和我根本没有重用的代码一样多.
在非日志记录特定上下文中表示,问题是:
如何在特征中声明实现类必须具有X类型的单例对象,并且必须通过方法def x:X访问此单例对象?
我不能简单地定义一个抽象方法,因为在类中只能有一个实现.我希望在超级类中登录让我获得超类单例,并且登录子类会让我获得子类单例.或者更简单地说,我希望登录Scala能像Java中的传统日志一样工作,使用特定于执行日志记录的类的静态记录器.我目前对Scala的了解告诉我,如果不像在Java中那样完全相同,这是不可能的,没有太多使用"更好"的Scala带来的好处.
oxb*_*kes 13
让我们首先明确一件事:如果你的特质看起来像这样:
trait Logger { lazy val log = Logger.getLogger }
Run Code Online (Sandbox Code Playgroud)
那么你还没有做的如下:
你已经做了如下:
请注意,即使您确实为每个类型的实例创建了一个单独的记录器(我经常这样做,即使我的程序包含数十万个这样的记录器,因此我对记录的控制非常精细),当然,既不会有性能也不会有内存问题!
一个"解决方案"是(当然),使伴侣对象实现记录器接口:
object MyType extends Logger
class MyType {
import MyType._
log.info("Yay")
}
Run Code Online (Sandbox Code Playgroud)
如何在特征中声明实现类必须具有X类型的单例对象,并且必须通过方法def x:X访问此单例对象?
声明必须由伴侣对象实现的特征.
trait Meta[Base] {
val logger = LoggerFactory.getLogger(getClass)
}
Run Code Online (Sandbox Code Playgroud)
为您的类创建基本特征,子类必须覆盖元方法.
trait Base {
def meta: Meta[Base]
def logger = meta.logger
}
Run Code Online (Sandbox Code Playgroud)
与同伴对象无关的类:
object Whatever extends Meta[Base]
class Whatever extends Base {
def meta = Whatever
def doSomething = {
logger.log("oops")
}
}
Run Code Online (Sandbox Code Playgroud)
通过这种方式,您只需要引用元对象.
我们可以使用像这样的Whatever类.
object Sample {
def main(args: Array[String]) {
val whatever = new Whatever
whatever.doSomething
}
}
Run Code Online (Sandbox Code Playgroud)