115

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

4

7 回答 7

84

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

伴随对象非常适合封装工厂方法之类的东西。例如,您可以让一个带有伴随对象的类承担工厂责任,而不是必须在任何地方都有FooFooFactory

于 2009-03-04T22:54:04.537 回答
64

伴随对象可用于存储类的所有实例共有的状态和方法,但它们不使用静态方法或字段。他们使用可以通过继承覆盖的常规虚拟方法。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
}

产生这个输出:

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
于 2010-08-20T12:16:35.337 回答
31

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

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

  2. 具有不同的可能参数集(与 Bloch 在 Effective Java 中写的关于伸缩构造函数的内容相比)

  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

我不会调用对象/基类 AbstractXxxxx 因为它看起来不错:就像创建抽象的东西一样。给这些名字一个真正的意义。考虑使用不可变、无方法、案例类并封装抽象基类。

于 2009-03-10T12:55:21.493 回答
19

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

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

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

于 2009-03-04T23:12:28.253 回答
3

我总是将伴随对象视为在 Scala 中编写函数式代码和面向对象代码的桥梁。很多时候,我们只需要接受一些输入并提供处理结果的纯函数。将这些相关函数放在伴随对象中可以很容易地查找和使用,对我自己以及在我的代码之上构建的一些人来说。

此外,它是一种语言提供的功能,可以在不做任何事情的情况下编写单例模式。当您需要一个单例来为 JVM 的生命周期封装委托者时,这尤其有用。例如,在 Scala 中编写一个简单的 HTTP 客户端库,您可以在其中封装基于 Java 实现的底层委托,并让 API 的使用者生活在纯粹的世界中。

于 2015-05-11T13:13:24.733 回答
0

如果您在同一个文件中以相同的名称定义类和对象,则它们称为伴生类和对象。Scala 没有 static 作为 JAVA 关键字,您可以将静态替换为 Scala 中的伴随类和对象。

有关更多详细信息,请查看 Scala 编程中的文章类和对象关键字

于 2017-06-22T17:56:35.877 回答
-1

首先,它提供了静态与非静态方法方法的清晰分离。还提供了一种创建单例类的简单方法。

它还可以从其他类和/或特征继承方法,这是 Java 静态方法无法做到的。并且可以作为参数传递。

于 2017-11-02T15:14:00.577 回答