我们知道,要想使用单例那么就必须定义私有构造函数来防止从类的外部来创建类的实例。在Scala中你也可以通过private关键字定义类的私有主构造函数来防止从类的外部创建类的实例。
scala> class Person private(name: String)
defined class Person
warning: previously defined object Person is not a companion to class Person.
Companions must be defined together; you may wish to use :paste mode for this.
scala> val p = new Person("Ming")
<console>:12: error: constructor Person in class Person cannot be accessed in object $iw
val p = new Person("Ming")
^
我们看到在类的外部已经无法使用new关键字来实例化这个类了。那么在Scala中如何实现getInstance方法来获取这个对象的实例呢,就是在类的伴生对象中实现这个方法。
scala> :paste
// Entering paste mode (ctrl-D to finish)
class Person private(name: String)
object Person {
def getInstance(name: String) = new Person(name)
}
// Exiting paste mode, now interpreting.
defined class Person
defined object Person
scala> val p = Person.getInstance("Ming")
p: Person = Person@7859bd9a
你可能发现了,这个时候Person并不是一个单例对象,而只是限制了主构造函数的访问权限。其实在Scala中实现一个单例对象最简单的方式就是直接使用类的伴生对象,而不需要定义类。当然你也可以像Java中那样去实现一个单例对象。你会看到不管你调用多少次getInstance方法,得到的都是同一个对象。
scala> :paste
// Entering paste mode (ctrl-D to finish)
class Person private(name: String)
object Person {
private var p:Option[Person] = None
def getInstance(name: String): Person = {
if (!p.isDefined) {
p = Some(new Person(name))
}
p.get
}
}
// Exiting paste mode, now interpreting.
defined class Person
defined object Person
scala> val p = Person.getInstance("Ming")
p: Person = Person@47d32e33
scala> val p = Person.getInstance("Li")
p: Person = Person@47d32e33