從 Java 到 Scala(二):object

本文由 Rhyme 發表在 ScalaCool 團隊博客。java

object是一種讓靜態迴歸常態、打破模式、自然的語言特性。程序員

其實在寫這篇文章以前,我思緒萬千,遲遲不能落筆,總想着本身會不會遺漏了某個知識點,或者有講得不太那麼準確的地方,可是後來我想明白了,學習同樣東西,最重要的並非要了解它的每個細節,而是要了解它的核心思想。若是你可以理解上面講的那句話,我想你或許也就掌握了objectapp

其實,object較之Java,更多的是一種思想設計理念上的昇華,就如同我原本就該有這東西,你卻須要我手動費很大地勁本身造出來同樣。ide

object當中,咱們能夠輕鬆的構建出一個「單例對象」,而在Java當中咱們一般得遵照一套「單例模式」的應用才能構建出一個單例對象。可是請你細想一番,「單例對象」難道不應是一種更加天然的存在嗎?學習

另外,和「單例對象」同樣,object當中的另外一個重量級的語言特性:「伴生對象」也一樣遵循這一套邏輯,讓「靜態」以一種更爲常態的形式存在。優化

單例對象(Singleton Object)

// 構建一個單例對象Singleton
object Singleton {
  var hello = "Hello World"
  def sayHello:String = {
    hello
  }
}
複製代碼

在Scala中,咱們使用關鍵字object來構建單例對象。任何用到單例模式的地方,你均可以用Scala的object來實現。如下代碼向你展現了在Scala中單例對象的基本使用。咱們只須要在咱們用到的地方引入咱們須要的「單例對象」便可。this

import Singleton._ //引入Singleton對象中的全部方法
class Test {
  def test:String = sayHello
}
複製代碼

伴生對象(Companion Object)

在Java中,咱們一般會用到既有實例方法又有靜態方法的類,在Scala中咱們能夠經過「伴生類」和「伴生對象」來實現。剛開始,你可能會對這兩個詞感到困惑,其實不用慌張,你徹底能夠在一開始用Java中的普通的不包含靜態的類來代替「伴生類」,用類中的全部的靜態來代替「伴生對象」。說的簡單一點,就是將Java類中的靜態搬到一個單例對象中。spa

下面分別用Java和伴生對象來實現下面這個簡單的售票功能。scala

使用Java實現的這段代碼,這裏就再也不多說,我想你確定比我還要熟悉。設計

public class TicketJava {
    private static int ticket = 10;
    private String name;
    public TicketJava(String name){
        this.name = name;
    }
    public static void sellTicketTo(String name){
        System.out.println(name + " get ticket " + ticket);
    }
    public void buyTicket() {
        sellTicketTo(name);
    }
}

複製代碼

如下是使用「伴生對象」實現的版本。你只須要關注一個細節,靜態所在的位置

類同名且與類在同一個源文件下object對象就是「伴生對象」,與之相對的類就叫作「伴生類」。

伴生對象與靜態實現的功能沒有二異,原來靜態所具有的特性,在「伴生對象」中都能找到。在Java中,靜態特性包裹在Class類中,它們能夠互訪私有特性,所以你也就能明白接下來的這句話:「伴生對象」與「伴生類」可以互訪私有特性

class Ticket(name: String) {// name 是類Ticket的成員變量
    
  // 在Scala中import語句能夠寫在任意地方
  // 所以你能夠控制import語句的做用範圍,使得代碼更加靈活
  import Ticket._

  def buyTicket(): Unit = {
    // 調用伴生對象中的方法
    sellTicketTo(name)
  }
}
// 伴生對象,和類同名,且在同一個源文件下,能夠互訪私有屬性
object Ticket {
  private var ticket: Int = 10

  def sellTicketTo(name: String): Unit = {
    println(f"$name get ticket $ticket")
    ticket = ticket - 1
  }
}
複製代碼

擴展類或特質的對象

特質:能夠理解爲Java中的接口

在Scala中,全部用object修飾的都是「單例對象」,咱們之後將用「單例對象」代替Scala中的對象這個概念。

關於單例對象,你須要記住一個核心的理念:共享。單例對象、單例模式,全部和單例相關的都離不開共享這個概念。或者說的更準確一點,是共享對象

對象在本質上能夠具有類的全部特性,由於類是對象的模板,對象不過是類的一個實例而已。而類有一個重要的特性:繼承或實現。在Scala中咱們會將繼承或實現稱做擴展類或特質。擴展使得類可以進行更好的抽象。在Java中咱們一般會對類執行擴展操做,可是在Scala中,自從單例對象被做爲一種更常態的特性,單例對象也能夠擴展類或特質來實現更多的功能。其中一個很典型的應用就是藉助單例對象的擴展來表示一些公共的狀態。

例如如下代碼:

咱們能夠經過用「單例對象」繼承指定的抽象結構來共享一些默認的狀態和對象。其實,關鍵的核心思想仍是兩個字共享

abstract class Status(var status: Int) {
  def operation()
}

object Ok extends Status(200) {
  override def operation(): Unit = println("Ok operation")
}

object Error extends Status(500) {
  override def operation(): Unit = println("Error operation")
}

複製代碼

與此相似的,咱們經過繼承Enumeration接口能夠在Scala中實現枚舉的功能。Scala默認沒有實現枚舉功能的。具體的這裏不進行講述,感興趣的能夠上網進行查詢。

總而言之,凡有共享這個概念的地方,你均可以考慮使用「單例對象」來實現。

apply方法

首先來看一段代碼

new Array[Person](new Person("Rhyme"),new Person("Captain"))
Array[Person](Person("Rhyme"),Person("Captain"))
複製代碼

你以爲哪一種形式更加簡潔直觀呢?第一種方式這裏再也不解釋,第二種方式,你會發現,咱們省去了new關鍵字。

咱們先無論具體的語言特性,單從代碼自己來看,你會更傾向於哪種?

很明顯,我會選擇第二種省去new關鍵字的方式。緣由很簡單:更加天然,更加簡潔。首先,做爲同行,想必new關鍵字咱們再熟悉不過了。敲了它不下一萬遍有沒有!敲了這麼多,你就沒有感受過嗎?

其實這個字很關鍵,一旦你寫某段代碼寫得煩了,就說明這段代碼自己就是存在題的。然而若是你以爲它並無什麼,那隻能說明你已經麻木了,做爲一個好的程序員,不該該麻木,咱們要想法設法,寫最關鍵的代碼

首先做爲一個全民公認的new操做,爲何我不能夠將new這個關鍵字從類名前面移去呢?注意咱們關注的應該是最關鍵的代碼new關鍵字對我來講,已是再熟悉不過的東西了,它對我已經沒有價值了,就讓他默認存在就行了,我不須要再看到它!

而這種能夠幫你省去new操做的語言特性咱們就可使用apply方法來實現。

咱們一般會在伴生對象中定義一個apply()方法,例如以下代碼:

class Person(name: String) {
}

object Person {
  def apply(name: String):Person = new Person(name)
}
複製代碼

apply方法將爲咱們返回一個「伴生類」的對象。當我門在執行Person("Rhyme")的時候,默認就會調用「伴生對象」中的apply()放回,併爲你返回一個建立好的對象。若是你不想使用apply()方法,本身定義一個更適合本身的工廠方法也是一個不錯的選擇。

class Person(name: String) {
}

object Person {
  def createPerson(name:String):Person = {
    new Person(name)
  }
}
複製代碼

迴歸常態

其實,以上這些特性,你發現沒有,Scala在底層的技術實現上,並無作太多的改變,將這些Scala代碼編譯,用javap來查看編譯以後的代碼,你會發現它利用的依然是原先Java中的那些代碼邏輯,只不過它一直在作優化,一直在簡化,讓單例靜態對象建立等語言特性迴歸它們應有的常態,讓他們成爲一種自然的語言特性存在着,就像魚兒之於大海同樣天然的存在着。

最後,再讓咱們回到最開始講的那句話:object是一種讓靜態迴歸常態、打破模式、自然的語言特性。 仔細再品味品味,你是否是又有一些新的體會呢!

在下一篇中,咱們會繼續探索object更加具體的應用,好比如何去改造Java傳統的工廠方法和模式。

相關文章
相關標籤/搜索