學(xué)習(xí)Scala的定義工廠對(duì)象
你現(xiàn)在有了布局元素的類層級(jí)。這個(gè)層級(jí)可以“依原件”展現(xiàn)給你的客戶。但是你或許還是選擇把層級(jí)隱藏在工廠對(duì)象之后。工廠對(duì)象包含了構(gòu)建其它對(duì)象的方法??蛻襞c實(shí)惠使用這些工廠方法實(shí)現(xiàn)對(duì)象的構(gòu)造而不是直接使用new構(gòu)造對(duì)象。這種方式的一個(gè)好處是對(duì)象的創(chuàng)建可以被集中化并且對(duì)象實(shí)際代表類的細(xì)節(jié)可以被隱藏。這種隱藏一方面簡(jiǎn)化客戶理解你的庫(kù),因?yàn)楦俚募?xì)節(jié)被暴露出來(lái),另一方面提供給你更多機(jī)會(huì)在之后改變庫(kù)的實(shí)現(xiàn)而不會(huì)破壞客戶代碼。
51CTO編輯推薦:Scala編程語(yǔ)言專題
為布局元素構(gòu)建工廠的第一任務(wù)是選擇工廠方法應(yīng)該放在哪兒。它們應(yīng)該是單例對(duì)象成員還是類成員?包含它們的對(duì)象或類應(yīng)該怎么調(diào)用?這里有許多可能性。最直接的方案是創(chuàng)建類Element的伴生對(duì)象并把它做成布局元素的工廠方法。對(duì)于這種方式,你唯一要暴露給客戶的就是Element的類/對(duì)象組合,隱藏它的三個(gè)實(shí)現(xiàn)類ArrayElement,LineElement和UniformElement。
代碼10.10是遵循了這個(gè)方案的設(shè)計(jì)。Element伴生對(duì)象包含了三個(gè)重載的elem方法變體。每一個(gè)變體構(gòu)建一種不同的布局對(duì)象。
代碼 10.10 帶有工廠方法的工廠對(duì)象
- 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)通過(guò)使用elem工廠方法實(shí)現(xiàn)而不用顯式地創(chuàng)建新的ArrayElement實(shí)例成為可能。為了不使用單例對(duì)象的名稱,Element,認(rèn)證而調(diào)用工廠方法,我們將在源文件頂上引用Element.elem。換句話說(shuō),代之以在Element類內(nèi)部使用Element.elem調(diào)用工廠方法,我們將引用Element.elem,這樣我們只要使用它們的簡(jiǎn)化名,elem,就可以調(diào)用工廠方法。代碼10.11展示了類Element在這些改變之后的樣子。
代碼 10.11 重構(gòu)以使用工廠方法的類Element
- import Element.elem
- abstract class Element {
- def contents: Array[String]
- def width: Int =
- if (height == 0) 0 else contents(0).length
- def height: Int = contents.length
- def above(that: Element): Element =
- elem(this.contents ++ that.contents)
- def beside(that: Element): Element =
- elem(
- for (
- (line1, line2) < - this.contents zip that.contents
- ) yield line1 + line2
- )
- override def toString = contents mkString "\n"
- }
而且,有了工廠方法之后,子類ArrayElement,LineElement和UniformElement現(xiàn)在可以是私有的,因?yàn)樗鼈儾辉傩枰苯颖豢蛻粼L問(wèn)。Scala里,你可以在類和單例對(duì)象中定義其它的類和單例對(duì)象。因此一種讓Element的子類私有化的方式就是把它們放在Element單例對(duì)象中并在那里聲明它們?yōu)樗接小P枰臅r(shí)候,這些類將仍然能被三個(gè)elem工廠方法訪問(wèn)。代碼10.12展示了其中的細(xì)節(jié)。
- object Element {
- private class ArrayElement(
- val contents: Array[String]
- ) extends Element
- private class LineElement(s: String) extends Element {
- val contents = 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.make(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)
- }
代碼 10.12 用私有類隱藏實(shí)現(xiàn)
【相關(guān)閱讀】