鍍金池/ 教程/ Scala/ 組合和繼承–定義 factory 對象
包對象
Ordered Trait
組合和繼承–定義 final 成員
基本數據類型
Match 表達式
類和對象 (三)
操作基本數據類型
for 表達式
組合和繼承–重載成員函數和方法
類和對象 (二)
組合和繼承–定義 factory 對象
組合和繼承–多態(tài)和動態(tài)綁定
Trait 的基本概念
if 表達式
組合和繼承–抽象類
函數–函數字面量的一些簡化寫法
while 循環(huán)
組合和繼承–使用組合還是繼承?
訪問控制修飾符
Trait 示例–Rectangular 對象
組合和繼承–定義參數化成員變量
組合和繼承–定義無參數方法
類和對象 (一)
函數–閉包
函數–類成員函數
Scala 基本數據類型的實現(xiàn)方法
try 表達式處理異常
選擇瘦接口還是胖接口設計?
組合和繼承–小結
創(chuàng)建新的控制結構
使用 import
為訪問控制修飾符添加作用域
Scala 的類層次關系
類和對象 (五)
傳名參數
柯里化函數
函數–頭等公民
組合和組合和繼承–定義 heighten 和 widen 函數
使用 Package–將代碼放入包中
隱含的 import
所有類的公共子類–底層類型
進一步 Scala
函數–局部函數
引用包中的代碼
組合和繼承–使用 override 修飾符
組合和繼承–實現(xiàn)類 Element 的 above,beside 和 toString()方法
類和對象 (四)
函數–尾遞歸
沒有“break”和“continue”的日子
組合和繼承–調用基類構造函數
減低代碼重復
函數–函數–可變參數,命名參數,缺省參數
起步 Scala
組合和繼承–擴展類
函數–部分應用的函數
開始神奇的 Scala編程之旅
組合和繼承–概述
Trait 用來實現(xiàn)可疊加的修改操作

組合和繼承–定義 factory 對象

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

實現(xiàn) factory 對象的一個基本方法是采用 singleton 模式,在 Scala 中,可以使用類的伴隨對象(companion 對象)來實現(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 的實現(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(類 Element 的伴隨對象),我們可以利用 Element 對象提供的 factory 方法,重新實現(xiàn)類 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"
}

這里我們重寫了 above 和 beside 方法,使用伴隨對象的 factory 方法 Element.elem 替代 new 構造函數。

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

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)
}