问题
Many classes in the Scala standard library use apply()
of their companion object as factory. This is often convenient when chaining calls like List(List(1))
. On the other hand, it's still possible to create objects directly with new
(new HashMap[Int, Int]()
).
That's standard library. Now, in my own code, which approach is better to use: companion factory or creating objects with new
?
Is there any convention on when to create companion object factory and when to do with the new
keyword?
What are the advantages of using one over the other?
回答1:
In most cases I use the companion object's apply
method, because the code looks less cluttered. However, there is at least one benefit of using a static factory. Consider the unimaginative type MyInt
which just wraps an Int
:
class MyInt(val i: Int)
I can obtain instances of MyInt
calling the constructor which will instantiate a new object each time the constructor is called. If my program relies heavy on MyInt
this results in a lot of instances created. Assuming most of the MyInt
I use are -1
, 0
, and 1
, since MyInt
is immutable I can reuse the same instances:
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)
}
}
So at least for immutable values there can be a technical advantage of using the static factory over calling the constructor. As an implication, if you want to express in code that a new instance is created, then use the new
keyword. Personally, I use the new
-keyword when creating objects, and the apply
-method when creating values, though I don't know if there is an official convention.
回答2:
I don't know that there is a general recommendation of one approach over the other, usually it is just a convenience not to have to type new
.
There are occasions, though, where the factory method option can be better. For example, if your class has a String field that must be uppercase, you can make the standard constructor private, forcing instantiation via the factory method which ensures the field is always uppercase:
class A private[A] (s: String)
object A {
def apply(s: String): A = new A(s.toUpperCase)
}
Note: if your class is a case class, there are a couple of other tweaks to get this to work fully - see here.
来源:https://stackoverflow.com/questions/32279539/when-to-use-companion-object-factory-versus-the-new-keyword