Если синглтоны-это так плохо, почему Скала есть языковая поддержка для них? [дубликат]


Возможный дубликат:
Почему одноэлементные объекты более ориентированы на объект?

Почему Scala имеет языковую поддержку для синглетного анти-паттерна? Если бы Scala унаследовала ключевое слово static от Java, какиедопустимые варианты использования ключевого слова object остались бы?

4 13

4 ответа:

Есть, по крайней мере, принципиальное отличие в том, что object в Scala на самом деле является объектом (то есть экземпляром), а не в Java, где это просто методы, вызываемые самим классом.

Это означает, что он избегает одной из главных претензий к синглетам - поскольку он является экземпляром, его можно передавать и подключать к методам, и поэтому его можно заменить для других реализаций во время тестов и т. д. Во всяком случае, это синтаксический сахар для рекомендуемой альтернативы singletons-наличие класса с методом getInstance(), возвращающим единственный экземпляр по умолчанию. Тем не менее, я считаю, что синглетный анти-паттерн больше связан с дизайном, чем с особенностями языка. Если вы структурируете свою кодовую базу таким образом, что некоторая монолитная зависимость неявно связана с большинством классов, то у вас будут проблемы с ее изменением - независимо от особенностей языка.

Существуют допустимые случаи использования objects в Scala (например, использование case objects для сообщений акторам, или если несколько из них расширяют sealed trait как альтернативу перечислениям). Языковой функцией можно злоупотреблять, но, на мой взгляд, она менее простительна, чем Java static, и более полезна.

Синглтоны без состояния не так уж и плохи. Я вижу объекты (в scala) как модули для размещения функций (поведения).

Если вы используете объект для удержания состояния, это случай, когда синглетоны являются катастрофой, потому что может не быть способа очистить его, и это один из главных примеров того, что синглетоны являются анти-паттерном. Объект без изменяемого состояния и с чистыми функциями гораздо менее склонен к причинению боли в этом отношении, ВОТ ПРИМЕР:

object StringSerializer extends Serializer[String] {
  // Implementation goes here.
}

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

Например, классы типов. Разница между статическими классами и синглетонами состоит в том, что синглеты являются объектами и могут передаваться как параметры. Этот код, например, не может быть построен со статическими классами:

trait TypeClass[A] {
  def method(x: A): A
}

implicit object IntTypeClass extends TypeClass[Int] {
  def method(x: Int) = x*x
}

def foo[A](x: A)(implicit tc: TypeClass[A]) = tc.method(x)

scala> foo(2)
res0: Int = 4