Как войти в Scala * без * ссылки на регистратор в * каждом экземпляре *? - PullRequest
21 голосов
/ 24 июня 2011

Я посмотрел пример регистрации в Scala, и он обычно выглядит так:

import org.slf4j.LoggerFactory

trait Loggable {
  private lazy val logger = LoggerFactory.getLogger(getClass)
  protected def debug(msg: => AnyRef, t: => Throwable = null): Unit =
    {...}
}

Это кажется независимым от конкретной структуры ведения журнала.В то время как это делает работу, оно также вводит посторонний ленивый val в каждом экземпляре , который хочет вести журналирование, которое вполне может быть каждым экземпляром всего приложения.Это кажется мне слишком тяжелым, в частности, если у вас много «маленьких экземпляров» определенного типа.

Есть ли способ поместить регистратор в объект конкретного класса, просто используя наследование?Если мне нужно явно объявить регистратор в объекте класса и явно ссылаться на него из класса / свойства, то я написал почти столько же кода, как если бы я вообще не использовал повторно.

Выраженная в контексте, не связанном с журналированием, проблема будет выглядеть следующим образом:

Как я могу объявить в признаке, что реализующий класс должен иметь одноэлементный объект типа X, и что этот одноэлементный объект должен быть доступен через методdef x: X?

Я не могу просто определить абстрактный метод, потому что в классе может быть только одна реализация.Я хочу, чтобы при входе в суперкласс я получал синглтон суперкласса, а при входе в подкласс я получал синглтон подкласса.Или, проще говоря, я хочу, чтобы регистрация в Scala работала так же, как традиционная регистрация в Java, с использованием статических регистраторов, специфичных для класса, выполняющего регистрацию.Мои нынешние знания о Scala говорят мне, что это просто невозможно без того, чтобы делать это точно так же, как вы делаете в Java, без особой пользы от использования «лучшего» Scala.

Ответы [ 4 ]

12 голосов
/ 24 июня 2011

Преждевременная оптимизация - корень всего зла

Давайте сначала проясним одно: если ваша черта выглядит примерно так:

trait Logger { lazy val log = Logger.getLogger }

Тогда то, что вы не сделали, выглядит следующим образом:

  • Вы НЕ создали экземпляр регистратора для экземпляра вашего типа
  • У вас нет ни памяти, ни проблем с производительностью (если у вас нет)

Что вы сделали сделали следующим образом:

  • У вас есть дополнительная ссылка в каждом экземпляре вашего типа
  • Когда вы впервые получаете доступ к логгеру, вы, вероятно, выполняете поиск по карте

Обратите внимание, что , даже если вы создали отдельный регистратор для каждого экземпляра вашего типа (что я часто делаю, даже если моя программа содержит сотни тысяч таких файлов, так что я очень хорошо точный контроль над моим журналом), у вас почти наверняка все равно не будет ни производительности, ни проблемы с памятью !

<Ч />

Одним из "решений" является (конечно), чтобы заставить сопутствующий объект реализовать интерфейс логгера:

object MyType extends Logger

class MyType {
  import MyType._
  log.info("Yay")
}
7 голосов
/ 24 июня 2011

Как я могу заявить, что реализующий класс должен иметь одноэлементный объект типа X, и это этот одноэлементный объект должен быть доступно через метод def x: X?

Объявите черту, которая должна быть реализована объектами вашего компаньона.

trait Meta[Base] {
  val logger = LoggerFactory.getLogger(getClass)
}

Создайте базовую черту для ваших классов, подклассы должны перезаписать мета-метод.

trait Base {
  def meta: Meta[Base]
  def logger = meta.logger
}

Класс Что бы ни было с сопутствующим объектом:

object Whatever extends Meta[Base]

class Whatever extends Base {
  def meta = Whatever

  def doSomething = {
    logger.log("oops")
  }
}

Таким образом, вам нужно иметь только ссылку на мета-объект.

Мы можем использовать любой класс, подобный этому.

object Sample {
  def main(args: Array[String]) {
    val whatever = new Whatever
    whatever.doSomething
  }
}
0 голосов
/ 24 июня 2011

Я думаю, что вы не можете автоматически получить соответствующий одноэлементный объект класса или требовать, чтобы такой одноэлементный объект существовал.

Одна из причин заключается в том, что вы не можете знать тип одноэлементного объекта до его определения.Не уверен, поможет ли это или это лучшее решение вашей проблемы, но если вы хотите, чтобы какой-то мета-объект был определен с определенной чертой, вы можете определить что-то вроде:

trait HasSingleton[Traits] {
  def meta: Traits
}

trait Log {
  def classname: String
  def log { println(classname) }
}

trait Debug {
  def debug { print("Debug") }
}

class A extends HasSingleton[Log] {
  def meta = A // Needs to be defined with a Singleton (or any object which inherits from Log}
  def f {
    meta.log
  }
}
object A extends Log {
  def classname = "A"
}

class B extends HasSingleton[Log with Debug] { // we want to use Log and Debug here
  def meta = B
  def g {
    meta.log
    meta.debug
  }
}
object B extends Log with Debug {
  def classname = "B"
}

(new A).f
// A
(new B).g
// B
// Debug
0 голосов
/ 24 июня 2011

Я не уверен, что полностью понимаю ваш вопрос. Поэтому я прошу прощения, если это не тот ответ, который вы ищете.

Определите object, куда вы положили logger, затем создайте компаньона trait.

object Loggable {
   private val logger = "I'm a logger"
}

trait Loggable {
   import Loggable._
   def debug(msg: String) {
      println(logger + ": " + msg)
   }
}

Так что теперь вы можете использовать его так:

scala> abstract class Abstraction
scala> class Implementation extends Abstraction with Loggable
scala> val test = new Implementation
scala> test.debug("error message")
I'm a logger: error message

Это отвечает на ваш вопрос?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...