Scala对象和单身人士的崛起

时间:2012-11-30 13:45:31

标签: scala functional-programming

一般风格问题。

随着我更好地编写功能代码,我的更多方法变成了纯函数。我发现很多我的“类”(松散意义上的代码容器)正在变得无国家。因此,我将它们设为对象而不是类,因为不需要实例化它们。

现在在Java世界中,拥有一个充满“静态”方法的类似乎很奇怪,并且通常只用于“帮助”类,就像你看到Guava和Commons- *等等。

所以我的问题是,在Scala世界中,在“对象”中有很多逻辑,而不是“类”非常正常,或者是否有另一个首选的习语。

3 个答案:

答案 0 :(得分:16)

正如您在标题中提到的,对象是单例类,而不是您在问题文本中提到的具有静态方法的类。

有一些东西可以使scala对象比java-world中的静态和单例更好,所以在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中,你知道一个对象是一个单例,你只能推断它的作用。

答案 1 :(得分:4)

您还可以使用包对象,例如看看这里的scala.math包对象 https://lampsvn.epfl.ch/trac/scala/browser/scala/tags/R_2_9_1_final/src//library/scala/math/package.scala

答案 2 :(得分:2)

是的,我会说这是正常的。

对于我的大多数类,我创建了一个伴随对象来处理那里的一些初始化/验证逻辑。例如,如果在构造函数中验证参数失败,则可以在配对对象apply-method中返回OptionEither,而不是抛出异常:

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
}