在Scala中使用伴随对象的理由是什么?

Rah*_*hul 101 oop scala companion-object

是否需要一个类的伴随对象(单例)?为什么我要创建一个类,比如说Foo并为它创建一个伴随对象?

Sae*_*aem 75

伴侣对象基本上提供了一个可以放置"静态"方法的地方.此外,伴随对象或伴随模块可以完全访问类成员,包括私有成员.

Companion对象非常适合封装工厂方法之类的东西.而不必有,例如,FooFooFactory无处不在,你可以有一个伴侣对象的类采取在工厂的责任.


Cra*_*lin 60

伴随对象对于存储类的所有实例共有的状态和方法很有用,但它们不使用静态方法或字段.它们使用常规虚拟方法,可以通过继承覆盖它们.Scala真的没有任何静态.有很多方法可以使用它,但这是一个简单的例子.

abstract class AnimalCounter
{
    var animals = 0

    def name: String

    def count()
    {
        animals += 1
        println("%d %ss created so far".format(animals, name))
    }
}

abstract class Animal
{
    def companion: AnimalCounter
    companion.count()
}

object Dog extends AnimalCounter
{
    val name = "dog"
}

class Dog extends Animal
{
    def companion = Dog
}

object Cat extends AnimalCounter
{
    val name = "cat"
}

class Cat extends Animal
{
    def companion = Cat
}
Run Code Online (Sandbox Code Playgroud)

哪个产生这个输出:

scala> new Dog
1 dogs created so far

scala> new Cat
1 cats created so far

scala> new Dog
2 dogs created so far

scala> new Cat
2 cats created so far
Run Code Online (Sandbox Code Playgroud)


Szy*_*him 30

...它是为伴随类存储静态工厂方法(而不是DP)的好地方.如果您命名那些重载的工厂方法apply(/ ... /),您将能够创建/初始化您的类

  1. 没有'新'(不是那么重要)

  2. 使用不同的可能参数集(与Bloch在Effective Java中关于telescoping构造函数的内容相比)

  3. 能够决定你想要创建哪个派生类而不是抽象(伴随)派生类

示例代码:

abstract class AbstractClass;
class RealThing(s: String) extends AbstractClass;
class AlternativeThing(i: Int) extends AbstractClass;
object AbstractClass {
  def apply(s: String) = {
    new RealThing(s)
  }
  def apply(i: Int) = {
    new AlternativeThing(i)
  }
}

// somewhere else you can
val vs = AbstractClass("asdf")  // gives you the RealThing wrapped over string
val vi = AbstractClass(123)  // gives you AlternativeThing wrapped over int
Run Code Online (Sandbox Code Playgroud)

我不会调用对象/基类AbstractXxxxx,因为它看起来并不坏:就像创建一些抽象的东西.给这些名字一个真正的意义.考虑使用不可变的,方法较少的case类并密封抽象基类.

  • `RealThing`和`AlternativeThing`类应该有一个`private`构造函数来强制用户使用`AbstractClass`工厂.`class AlternativeThing private(i:Int)扩展了AbstractClass` (2认同)

Fab*_*eeg 19

除了Saem在回复中所说的内容之外,Scala编译器还在相应的伴随对象(源或目标)中查找类型的隐式转换,因此不需要导入转换.

关于单例对象的原因一般Scala中的编程说:

如第1章所述,Scala比Java更面向对象的一种方式是Scala中的类不能有静态成员.相反,Scala有单例对象(第65页).