Scala 組合和繼承–定義 factory 對(duì)象

2018-09-28 18:20 更新

組合和繼承–定義 factory 對(duì)象

到目前為止,我們定義了關(guān)于布局元素類(lèi)的一個(gè)層次結(jié)構(gòu)。你可以把包含這個(gè)層次關(guān)系的類(lèi)作為 API 接口提供給其它應(yīng)用,但有時(shí)你可以希望對(duì)函數(shù)庫(kù)的用戶(hù)隱藏這種層次關(guān)系,這通??梢允褂?factory(構(gòu)造工廠)對(duì)象來(lái)實(shí)現(xiàn)。一個(gè) factory 對(duì)象定義了用來(lái)構(gòu)造其它對(duì)象的函數(shù)。庫(kù)函數(shù)的用戶(hù)可以通過(guò)工廠對(duì)象來(lái)構(gòu)造新對(duì)象,而不需要通過(guò)類(lèi)的構(gòu)造函數(shù)來(lái)創(chuàng)建類(lèi)的實(shí)例。使用工廠對(duì)象的好處是,可以統(tǒng)一創(chuàng)建對(duì)象的接口并且隱藏被創(chuàng)建對(duì)象具體是如何來(lái)表示的。這種隱藏可以使得你創(chuàng)建的函數(shù)庫(kù)使用變得更簡(jiǎn)單和易于理解,也正是隱藏部分實(shí)現(xiàn)細(xì)節(jié),可以使你有機(jī)會(huì)修改庫(kù)的實(shí)現(xiàn)而不至于影響庫(kù)的接口。

實(shí)現(xiàn) factory 對(duì)象的一個(gè)基本方法是采用 singleton 模式,在 Scala 中,可以使用類(lèi)的伴隨對(duì)象(companion 對(duì)象)來(lái)實(shí)現(xiàn)。比如:

object Element {
  def elem(contents: Array[String]):Element =
   new ArrayElement(contents)
  def elem(chr:Char, width:Int, height:Int) :Element =
    new UniformElement(chr,width,height)
  def elem(line:String) :Element =
    new LineElement(line)
}

我們先把之前 Element 的實(shí)現(xiàn)列在這里:

abstract class Element {
  def contents: Array[String]
  def height: Int = contents.length
  def width: Int = if (height == 0) 0 else contents(0).length
  def above(that: Element) :Element =
    new ArrayElement(this.contents ++ that.contents)
  def beside(that: Element) :Element = {
    new ArrayElement(
      for(
        (line1,line2) <- this.contents zip that.contents
      ) yield line1+line2
    )
  }
  override def toString = contents mkString "\n"
}

有了 object Element(類(lèi) Element 的伴隨對(duì)象),我們可以利用 Element 對(duì)象提供的 factory 方法,重新實(shí)現(xiàn)類(lèi) Element 的一些方法:

abstract class Element {
  def contents: Array[String]
  def height: Int = contents.length
  def width: Int = if (height == 0) 0 else contents(0).length
  def above(that: Element) :Element =
    Element.elem(this.contents ++ that.contents)
  def beside(that: Element) :Element = {
    Element.elem(
      for( 
        (line1,line2) <- this.contents zip that.contents
      ) yield line1+line2
    ) 
  }
  override def toString = contents mkString "\n"
}

這里我們重寫(xiě)了 above 和 beside 方法,使用伴隨對(duì)象的 factory 方法 Element.elem 替代 new 構(gòu)造函數(shù)。

這樣修改之后,庫(kù)函數(shù)的用戶(hù)不要了解 Element 的繼承關(guān)系,甚至不需要知道類(lèi) ArrayElement,LineElement 定義的存在,為了避免用戶(hù)直接使用 ArrayElement 或 LineElement 的構(gòu)造函數(shù)來(lái)構(gòu)造類(lèi)的實(shí)例,因此我們可以把 ArrayElement,UniformElement 和 LineElement 定義為私有,定義私有可以也可以把它們定義在類(lèi) Element 內(nèi)部(嵌套類(lèi))。下面為這種方法的使用:

object Element {
  private class ArrayElement(val contents: Array[String])
    extends Element {
  }
  private class LineElement(s:String) extends ArrayElement(Array(s)) {
    override def width = s.length
    override def height = 1
  }
  private class UniformElement (ch :Char,
    override val width:Int,
    override val height:Int
  ) extends Element{
    private val line=ch.toString * width
    def contents = Array.fill(height)(line)
  }
  def elem(contents: Array[String]):Element =
   new ArrayElement(contents)
  def elem(chr:Char, width:Int, height:Int) :Element =
    new UniformElement(chr,width,height)
  def elem(line:String) :Element =
    new LineElement(line)
}
以上內(nèi)容是否對(duì)您有幫助:
在線(xiàn)筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)