1. 程式人生 > 實用技巧 >scala之旅-核心語言特性【單例物件】(十五)

scala之旅-核心語言特性【單例物件】(十五)

object 是一個類有且唯一的例項。當物件被引用時,它是懶模式建立的,就像 lazy val一樣。

作為一個頂級的值,物件是單例的。

作為一個封閉類的成員或者區域性值時,它的行為更像是一個lazy val。

定義一個單例的物件

物件是一個值。定義一個物件看起來像定義一個類,但是是用關鍵字 object:

object Box

下面是一個關於物件的例子,這個物件有一個方法:

package logging

object Logger {
  def info(message: String): Unit = println(s"INFO: $message")
}

這個info 方法可以被程式的任何地方匯入。像這樣建立一個實用方法是對單例物件的普遍使用方式。

讓我們看看如何在其他包中使用info方法:

import logging.Logger.info

class Project(name: String, daysToComplete: Int)

class Test {
  val project1 = new Project("TPS Reports", 1)
  val project2 = new Project("Website redesign", 5)
  info("Created projects")  // Prints "INFO: Created projects"
}

通過import語句 import logging.Logger.info,info方法就可以被訪問。

import 需要一個全路徑,物件也是全路徑匯入。

注意:如果一個物件不是頂級的,但是是內嵌在其他類或者物件裡面的,那麼這個物件的需要用 全路徑+依賴的方式,與類其他成員訪問方式一樣。這意味著給定兩種飲料類,類 Milk和類 OrangeJuice, 一個類成員 object NutritionInfo 依賴於封閉的例項,無論是 milk 還是 orangeJuice,milk.NutritionInfo 和oj.NutritionInfo 都是不一樣的。

物件的比較

與類同名的物件稱之為伴生物件。相反,這個類稱之為伴生類。伴生類或物件可以訪問與其伴生的內部私有成員。將伴生物件用於伴生類例項中沒有指明的方法和值。

import scala.math._

case class Circle(radius: Double) {
  import Circle._
  def area: Double = calculateArea(radius)
}

object Circle {
  private def calculateArea(radius: Double): Double = Pi * pow(radius, 2.0)
}

val circle1 = Circle(5.0)

circle1.area

這裡的類 Circle有一個在例項指定的area成員,單例物件Circle有一個 calculateArea方法,這個方法每個例項都可以訪問。

伴生物件當然也可以包含工廠方法:

class Email(val username: String, val domainName: String)

object Email {
  def fromString(emailString: String): Option[Email] = {
    emailString.split('@') match {
      case Array(a, b) => Some(new Email(a, b))
      case _ => None
    }
  }
}

val scalaCenterEmail = Email.fromString("[email protected]")
scalaCenterEmail match {
  case Some(email) => println(
    s"""Registered an email
       |Username: ${email.username}
       |Domain name: ${email.domainName}
     """.stripMargin)
  case None => println("Error: could not parse email")
}

這個物件 Email 包含一個工廠 fromString 用來從一個字串中建立一個Email。 以防解析錯誤,我們用一個 Option[Email] 返回。

注:如果一個類或物件有伴生,那麼它們必須在一個檔案裡面定義。要在REPL中定義伴生,請在同一行上定義它們或進入:paste模式 【注:這句話我沒看懂~】

Java開發者注意

java的static 成員被建模在scala的伴生物件的普通成員。

當從java程式碼中使用伴生物件時,伴生物件成員將會在伴生類裡面用一個static進行定義。這叫做靜態轉化,這個一般出現在即使你沒有定義伴生類的時候。