你现在有了布局元素的类层级。这个层级可以“依原件”展现给你的客户。但是你或许还是选择把层级隐藏在工厂对象之后。工厂对象包含了构建其它对象的方法。客户与实惠使用这些工厂方法实现对象的构造而不是直接使用new构造对象。这种方式的一个好处是对象的创建可以被集中化并且对象实际代表类的细节可以被隐藏。这种隐藏一方面简化客户理解你的库,因为更少的细节被暴露出来,另一方面提供给你更多机会在之后改变库的实现而不会破坏客户代码。
51CTO编辑推荐:Scala编程语言专题
为布局元素构建工厂的第一任务是选择工厂方法应该放在哪儿。它们应该是单例对象成员还是类成员?包含它们的对象或类应该怎么调用?这里有许多可能性。最直接的方案是创建类Element的伴生对象并把它做成布局元素的工厂方法。对于这种方式,你唯一要暴露给客户的就是Element的类/对象组合,隐藏它的三个实现类ArrayElement,LineElement和UniformElement。
代码10.10是遵循了这个方案的设计。Element伴生对象包含了三个重载的elem方法变体。每一个变体构建一种不同的布局对象。
代码 10.10 带有工厂方法的工厂对象
- 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的实现通过使用elem工厂方法实现而不用显式地创建新的ArrayElement实例成为可能。为了不使用单例对象的名称,Element,认证而调用工厂方法,我们将在源文件顶上引用Element.elem。换句话说,代之以在Element类内部使用Element.elem调用工厂方法,我们将引用Element.elem,这样我们只要使用它们的简化名,elem,就可以调用工厂方法。代码10.11展示了类Element在这些改变之后的样子。
代码 10.11 重构以使用工厂方法的类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现在可以是私有的,因为它们不再需要直接被客户访问。Scala里,你可以在类和单例对象中定义其它的类和单例对象。因此一种让Element的子类私有化的方式就是把它们放在Element单例对象中并在那里声明它们为私有。需要的时候,这些类将仍然能被三个elem工厂方法访问。代码10.12展示了其中的细节。
- 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 用私有类隐藏实现
【相关阅读】