是否需要一个类的伴随对象(单例)?为什么我要创建一个类,比如说Foo
并为它创建一个伴随对象?
伴侣对象基本上提供了一个可以放置"静态"方法的地方.此外,伴随对象或伴随模块可以完全访问类成员,包括私有成员.
Companion对象非常适合封装工厂方法之类的东西.而不必有,例如,Foo
和FooFactory
无处不在,你可以有一个伴侣对象的类采取在工厂的责任.
伴随对象对于存储类的所有实例共有的状态和方法很有用,但它们不使用静态方法或字段.它们使用常规虚拟方法,可以通过继承覆盖它们.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
...它是为伴随类存储静态工厂方法(而不是DP)的好地方.如果您命名那些重载的工厂方法apply(/ ... /),您将能够创建/初始化您的类
没有'新'(不是那么重要)
使用不同的可能参数集(与Bloch在Effective Java中关于telescoping构造函数的内容相比)
能够决定你想要创建哪个派生类而不是抽象(伴随)派生类
示例代码:
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,因为它看起来并不坏:就像创建一些抽象的东西.给这些名字一个真正的意义.考虑使用不可变的,方法较少的case类并密封抽象基类.
除了Saem在回复中所说的内容之外,Scala编译器还在相应的伴随对象(源或目标)中查找类型的隐式转换,因此不需要导入转换.
关于单例对象的原因一般Scala中的编程说:
如第1章所述,Scala比Java更面向对象的一种方式是Scala中的类不能有静态成员.相反,Scala有单例对象(第65页).