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

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

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

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

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


person Mifeet    schedule 28.08.2015    source источник
comment
Потому что использование new похоже на ношение цилиндра или подтяжек. Это стильно для определенного стиля, но не очень современно. Фабрика-компаньон — пара джинсов в стиле кэжуал.   -  person som-snytt    schedule 29.08.2015


Ответы (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 при создании значений, хотя я не знаю, существует ли официальное соглашение.

person Kulu Limpa    schedule 29.08.2015
comment
Мне нравится идея с кэшированием значений. Извлеченный урок заключается в том, что вы можете легко изменить реализацию apply(), чтобы делать все, что хотите, но когда вы используете new, вы всегда должны получать новый экземпляр. - person Mifeet; 29.08.2015

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

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

class A private[A] (s: String)

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

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

person Shadowlands    schedule 28.08.2015
comment
Как деталь внедрения, private[A] приводит к публичному ctor. Более привычно просто для private, так как это означает то же самое для Scala, но имеет частный ctor для Java. - person som-snytt; 29.08.2015
comment
У меня не так много опыта работы со Scala, но не утомительно ли писать дополнительный компаньон для каждого объекта? - person Mifeet; 29.08.2015
comment
Классы @Mifeet Case предоставляют (обычно) подходящий объект-компаньон бесплатно, поэтому, как правило, это совсем не беспокоит. - person Shadowlands; 30.08.2015
comment
Да, но мне не нужен класс case для службы с несколькими зависимостями. Возможно, мы могли бы провести границу между классами реализации, связанными управлением DI (new), и другими классами, динамически создаваемыми после запуска (фабрика)? - person Mifeet; 30.08.2015
comment
Конечно, звучит как разумное разделение. Я бы сказал, что кажется правильным для данного проекта/команды. - person Shadowlands; 30.08.2015