Когда использовать фабрику сопутствующих объектов по сравнению с новым ключевым словом

Многие классы в стандартной библиотеке Scala используют apply() их сопутствующий объект как фабрика. Это часто удобно, когда цепочки вызовов, такие как List(List(1)), С другой стороны, все еще возможно создавать объекты непосредственно с new (new HashMap[Int, Int]()).

Это стандартная библиотека. Теперь, в моем собственном коде, какой подход лучше использовать: фабрика-компаньон или создание объектов с new?

Есть ли соглашение о том, когда создавать фабрику сопутствующих объектов и когда делать с new ключевое слово?

Каковы преимущества использования одного над другим?

2 ответа

Решение

В большинстве случаев я использую объект-компаньон apply метод, потому что код выглядит менее загроможденным. Однако есть как минимум одно преимущество использования статической фабрики. Рассмотрим невообразимый тип MyInt который просто оборачивает Int:

class MyInt(val i: Int) 

Я могу получить примеры MyInt вызов конструктора, который будет создавать новый объект каждый раз, когда вызывается конструктор. Если моя программа сильно зависит от MyInt это приводит к созданию множества экземпляров. Предполагая, что большинство MyInt Я использую -1, 0, а также 1, поскольку MyInt неизменен, я могу использовать те же экземпляры:

class MyInt(val i: Int) 

object MyInt {
  val one = new MyInt(1)
  val zero = new MyInt(0)
  val minusOne = new MyInt(-1)

  def apply(i: Int) = i match {
    case -1 => minusOne
    case 0 => zero
    case 1 => one
    case _ => new MyInt(i)
  }
}

Поэтому, по крайней мере, для неизменяемых значений может быть техническое преимущество использования статической фабрики перед вызовом конструктора. Как следствие, если вы хотите выразить в коде, что создается новый экземпляр, то используйте new ключевое слово. Лично я использую newключевое слово при создании объектов, а apply-метод при создании ценностей, хотя я не знаю, существует ли официальное соглашение.

Я не знаю, что есть общая рекомендация одного подхода над другим, обычно это просто удобство, чтобы не печатать new,

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

class A private[A] (s: String)

object A {
    def apply(s: String): A = new A(s.toUpperCase)
}

Примечание: если ваш класс является классом case, есть пара других настроек, чтобы заставить его работать полностью - см. Здесь.

Другие вопросы по тегам