Подтвердить что ты не робот

Scala Объекты и рост одиночных чисел

Общий стиль.

Как только я стал лучше писать функциональный код, больше моих методов становятся чистыми функциями. Я нахожу, что многие мои "классы" (в свободном смысле контейнера кода) становятся свободными от государства. Поэтому я создаю им объекты вместо классов, так как нет необходимости их создавать.

Теперь в мире Java наличие класса с "статическими" методами показалось бы довольно странным и обычно используется только для "вспомогательных" классов, как вы видите с Guava и Commons- * и так далее.

Итак, мой вопрос заключается в том, что в мире Scala есть много логики внутри "объектов", а не "классы", вполне нормальные, или есть другая предпочтительная идиома.

4b9b3361

Ответ 1

Как вы упоминаете в своем названии, объекты - это одноэлементные классы, а не классы со статическими методами, как вы упомянули в тексте своего вопроса.

И есть несколько вещей, которые делают объекты scala лучше, чем статические и одиночные в java-мире, поэтому вполне "нормально" использовать их в scala.

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

scala> trait Quack {def quack="quack"}
defined trait Quack

scala> class Duck extends Quack
defined class Duck

scala> object Quacker extends Quack {override def quack="QUAACK"}
defined module Quacker

// MakeItQuack expects something implementing Quack
scala> def MakeItQuack(q: Quack) = q.quack
MakeItQuack: (q: Quack)java.lang.String

// ...it can be a class
scala> MakeItQuack(new Duck)
res0: java.lang.String = quack

// ...or it can be an object
scala> MakeItQuack(Quacker)
res1: java.lang.String = QUAACK

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

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

Кроме того, шаблон, который вы должны повторить во всех java-синглонах, дает две обязанности класса: обеспечить только один экземпляр себя и делать то, что он должен делать. Тот факт, что scala имеет декларативный способ указать, что что-то является синглоном, освобождает класс и программиста от нарушения принципа единой ответственности. В scala вы знаете, что объект является синглом, и вы можете просто рассуждать о том, что он делает.

Ответ 3

Да, я бы сказал, что это нормально.

Для большинства моих классов я создаю объект-компаньон для обработки некоторой логики инициализации/проверки. Например, вместо того, чтобы бросать исключение, если валидация параметров не выполняется в конструкторе, можно возвратить Option или Either в методе-компаньоне apply-method:

class X(val x: Int) {
  require(x >= 0)
}
// ==>
object X {
  def apply(x: Int): Option[X] =
    if (x < 0) None else Some(new X(x))
}
class X private (val x: Int)

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

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

object X {
  def doSomething(s: String) = ???
}
case class C(s: String)

class A extends Actor {
  var calculateLater: String = ""
  def receive = {
    case X => X.doSomething(s)
    case C(s) => calculateLater = s
  }
}

Другим вариантом использования объектов является уменьшение объема элементов:

// traits with lots of members
trait A
trait B
trait C

trait Trait {

  def validate(s: String) = {
    import validator._
    // use logic of validator
  }

  private object validator extends A with B with C {
    // all members of A, B and C are visible here
  }
}

class Class extends Trait {
  // no unnecessary members and name conflicts here
}