【Scala】单例对象与伴生对象

Scala的单例对象

Scala不能定义静态成员,而是代之定义单例对象(singleton object)。以object关键字定义。
对象定义了某个类的单个实例,包含了你想要的特性:

object Accounts{
    private var lastNumber = 0
    def newUniqueNumber() = { lastNumber += 1; lastNumber}
}

当你在应用程序中需要一个新的唯一账号时,调用Account.newUniqueNumber()即可。
对象的构造器在该对象第一次被使用时调用。

在下面几个场景下可以使用Scala单例对象:
- 作为存放工具函数或常量的地方
- 高效地共享单个不可变实例
- 需要使用单个实例来协调某个服务时

类和单例对象间的差别是,单例对象不带参数,而类可以。因为单例对象不是用new关键字实例化的,所以没机会传递给它实例化参数。每个单例对象都被实现为虚拟类(synthetic class)的实例,并指向静态的变量,因为它们与Java静态类有相同的初始化语义。

独立对象(standalone object)

不与伴生类共享名称的单例对象称为独立对象。它可以用在很多地方,例如作为相关功能方法的工具类,或者定义Scala应用的入口点。

伴生对象(companion object)

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

class Account {
    val id = Account.newUniqueNumber()
    private var balance = 0.0
    def deposit(amount: Double){ balance += amount }
    ...
}

object Account { //伴生对象
        private var lastNumber = 0
        def newUniqueNumber() = { lastNumber += 1; lastNumber}
    }

注意

  • 类的伴生对象可以被访问,但并不在作用域当中。Account类必须通过Account.newUniqueNumber()来调用伴生对象的方法。
  • 在REPL中,要同时定义类和对象,必须用粘贴模式。键入:paste,然后键入或粘贴类和对象的定义,最后一Ctrl+D退出粘贴模式。

将伴生对象作为工厂使用

我们通常将伴生对象作为工厂使用。
下面是一个简单的例子,可以不需要使用’new’来创建一个实例了。

class Bar(foo: String)

object Bar {
  def apply(foo: String) = new Bar(foo)
}

继承自类和特质的单例对象

一个object可以扩展类以及一个或多个特质,其结果是一个扩展了指定类以及特质的类的对象,同时拥有在对象定义中给出的所有特性。

继承自抽象类的例子

扩展类的一个有用的使用场景是给出可被共享的缺省对象。举例来说,考虑在程序中引入一个可撤销动作的类:

abstract class UndoableAction(val description: Sting) {
    def undo(): Unit
    def redo(): Unit
}

object DoNothingAction extends UndoableAction("Do nothing") {
    override def undo() {}
    override def redo() {}
}

//打开和保存功能尚未实现
val action = Map("open" -> DoNothingAction, "save" -> DoNothingAction, ...)

DoNothingAction对象可以被所有需要这个缺省行为的地方共用

混入特质的例子

有时,你可以混入像debugger或logging之类的特质来构建对象帮助调试对象,这样使得构建的对象实例具有log之类的方法:

trait Debugger {
    def log(message: String){
        //do something with message
    }
}

//no debugger
val child = new Child

//debugger added as the object is created
val problemChild = new ProblemChild with Debugger

转载请注明作者Jason Ding及其出处
GitCafe博客主页(http://jasonding1354.gitcafe.io/)
Github博客主页(http://jasonding1354.github.io/)
CSDN博客(http://blog.csdn.net/jasonding1354)
简书主页(http://www.jianshu.com/users/2bd9b48f6ea8/latest_articles)
百度搜索jasonding1354进入我的博客主页

推荐阅读更多精彩内容

  • 读《快学Scala 》一书的摘要 Scala 运行于JVM之上,拥有海量类库和工具,兼顾函数式编程和面向对象。 在...
    abel_cao阅读 947评论 0 8
  • 这篇讲义只讲scala的简单使用,目的是使各位新来的同事能够首先看懂程序,因为 scala 有的语法对于之前使用习...
    MrRobot阅读 2,241评论 0 10
  • 不属于类单个实例的方法和值属于单例对象,用关键字object而不用class来标记。 这个sum方法是全局可用的,...
    steanxy阅读 1,253评论 0 0
  • 姓名:潘律 组别:272期 乐观四组 【日精进打卡第23天】 【知~学习】 1、背诵大学,六项精进。 【我的座右铭...
    谦德阅读 49评论 0 0
  • 如何做一个坚定不移的败家子。 这是一篇适合给本来就不喜欢节俭的同学看,让你大手大脚时更加理直气壮,而天性热爱节俭的...
    曼季风阅读 97评论 0 0