【问题标题】:When to use companion object factory versus the new keyword何时使用伴随对象工厂与 new 关键字
【发布时间】:2015-08-28 20:48:10
【问题描述】:

Scala 标准库中的许多类都使用其伴随对象的apply() 作为工厂。这在链接像List(List(1)) 这样的调用时通常很方便。另一方面,仍然可以直接使用new (new HashMap[Int, Int]()) 创建对象。

这是标准库。现在,在我自己的代码中,哪种方法更好用:伴随工厂还是使用new 创建对象?

对于何时创建伴随对象工厂以及何时使用new 关键字是否有任何约定?

使用一个比另一个有什么优势?

【问题讨论】:

  • 因为使用new就像戴着礼帽或吊带。它对于某种风格来说很时尚,但不是很现代。配套工厂是一条休闲版型牛仔裤。

标签: scala conventions companion-object


【解决方案1】:

在大多数情况下,我使用伴随对象的apply 方法,因为代码看起来不那么混乱。但是,使用静态工厂至少有一个好处。考虑只包装了Int 的没有想象力的类型MyInt

class MyInt(val i: Int) 

我可以获得MyInt 调用构造函数的实例,该构造函数将在每次调用构造函数时实例化一个新对象。如果我的程序严重依赖MyInt,这会导致创建大量实例。假设我使用的大部分MyInt-101,因为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-keyword,在创建值时使用apply-method,虽然我不知道是否有官方约定。

【讨论】:

  • 我喜欢价值缓存的想法。吸取的教训是,您可以轻松更改 apply() 的实现以做任何您想做的事情,但是当您使用 new 时,您必须始终以一个新实例结束。
【解决方案2】:

我不知道是否有一种方法优于另一种方法的一般建议,通常只是为了方便而不必输入new

不过,在某些情况下,工厂方法选项可能会更好。例如,如果您的类有一个必须为大写的 String 字段,您可以将标准构造函数设为私有,通过工厂方法强制实例化,确保该字段始终为大写:

class A private[A] (s: String)

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

注意:如果您的课程是案例课程,还有一些其他的调整可以让它充分发挥作用 - 请参阅 here

【讨论】:

  • 作为一个 impl 细节,private[A] 会产生一个公共 ctor。更常见于private,因为它对 Scala 的含义相同,但有一个用于 Java 的私有 ctor。
  • 我对 Scala 没有太多经验,但是为每个对象编写额外的伴侣不是很麻烦吗?
  • @Mifeet Case 类免费提供(通常)合适的伴生对象,所以通常它一点也不麻烦。
  • 是的,但我不希望有多个依赖项的服务的案例类。也许我们可以在由 DI 管理 (new) 连接的实现类与启动后动态创建的其他类(工厂)之间划清界限?
  • 当然,听起来是一个合理的划分。我会说任何适合给定项目/团队的东西。
猜你喜欢
  • 2017-02-26
  • 2012-04-05
  • 2011-12-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-06-08
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多