Scala单例与伴生对象

时间:2021-07-24 23:10:29

Scala比Java更面向对象的一个方面是Scala没有静态成员。替代品是,Scala有单例对象:singleton object。

当单例对象与某个类共享同一个名称时,他被称作是这个类的伴生对象:companion object。你必须在同一个源文件里定义类和它的伴生对象。类被称为是这个单例对象的伴生类:companion class。类和它的伴生对象可以互相访问其私有成员。

定义单例对象不是定义类型(在Scala的抽象层次上说)

类和单例对象间的一个差别是,单例对象不带参数,而类可以。因为你不能用new关键字实例化一个单例对象,你没机会传递给它参数。每个单例对象都被作为由一个静态变量指向的虚构类:synthetic class的一个实例来实现,因此它们与Java静态类有着相同的初始化语法。Scala程序特别要指出的是,单例对象会在第一次被访问的时候初始化。

不与伴生类共享名称的单例对象被称为孤立对象:standalone object。最常见的就是程序入口:

object AbstractTypeTest1 extendsApplication {
  def newIntSeqBuf(elem1: Int, elem2: Int): IntSeqBuffer =
    newIntSeqBuffer {
         type T = List[U]
         val element = List(elem1, elem2)
       }
  val buf = newIntSeqBuf(7,8)
  println("length = " + buf.length)
  println("content = " + buf.element)
}

一个伴生对象的示例:

importscala.collection.mutable.Map
 
classChecksumAccumulator { 
    privatevar sum = 0
    def add(b: Byte) { 
        sum += b 
    }
    def checksum(): Int = ~(sum & 0xFF) + 1
}
object ChecksumAccumulator { 
    privateval cache = Map[String, Int]() 
    def calculate(s: String): Int = 
    if(cache.contains(s))
        cache(s)
    else{
        val acc = newChecksumAccumulator
        for(c <- s) acc.add(c.toByte) 
        val cs = acc.checksum() 
        cache += (s -> cs) 
        cs
    }
}
object Summer { 
    def main(args: Array[String]) { 
        println(ChecksumAccumulator.calculate("Every value is an object."))
    }
}

输出为:

-248

但是伴生对象如何体现单例的呢?

单例模式就控制类实例的个数f会。一个简单示例:

classWorkerprivate{
  def work() = println("I am the only worker!")
}
 
object Worker{
  val worker = newWorker
  def GetWorkInstance() : Worker = {
    worker.work()
    worker
  }
}
 
object Job{
  def main(args: Array[String]) { 
        for(i <- 1to5) {
          Worker.GetWorkInstance();
        }
    }
}

class Worker private声明了Worker的首构造函数是私有的,这样Worker的所有构造函数都不能直接被外部调用,因为所有从构造函数都会首先调用其他构造函数(可以是主构造函数,也可以是从构造函数),结果就是主构造函数是类的唯一入口点。

另一方面,Worker.GetWorkInstance();有点类似静态函数调用,但在Scala中这是不对的。Scala会隐式地调用apply来创建一个伴生对象的实例。Scala是一个纯粹的面向对象语言,不允许有任何破坏对象模型的机制存在,比如类的静态变量、函数等。