学习Scala的定义工厂对象

开发 后端
本文节选自Martin Odersky,Lex Spoon和Bill Venners所著,Regular翻译的《Programming in Scala》的第十章。Scala是一种针对 JVM 将函数和面向对象技术组合在一起的编程语言。

你现在有了布局元素的类层级。这个层级可以“依原件”展现给你的客户。但是你或许还是选择把层级隐藏在工厂对象之后。工厂对象包含了构建其它对象的方法。客户与实惠使用这些工厂方法实现对象的构造而不是直接使用new构造对象。这种方式的一个好处是对象的创建可以被集中化并且对象实际代表类的细节可以被隐藏。这种隐藏一方面简化客户理解你的库,因为更少的细节被暴露出来,另一方面提供给你更多机会在之后改变库的实现而不会破坏客户代码。

51CTO编辑推荐:Scala编程语言专题

为布局元素构建工厂的第一任务是选择工厂方法应该放在哪儿。它们应该是单例对象成员还是类成员?包含它们的对象或类应该怎么调用?这里有许多可能性。最直接的方案是创建类Element的伴生对象并把它做成布局元素的工厂方法。对于这种方式,你唯一要暴露给客户的就是Element的类/对象组合,隐藏它的三个实现类ArrayElement,LineElement和UniformElement。

代码10.10是遵循了这个方案的设计。Element伴生对象包含了三个重载的elem方法变体。每一个变体构建一种不同的布局对象。

  1. object Element {  
  2. def elem(contents: Array[String]): Element =  
  3. new ArrayElement(contents)  
  4. def elem(chr: Char, width: Int, height: Int): Element =  
  5. new UniformElement(chr, width, height)  
  6. def elem(line: String): Element =  
  7. new LineElement(line)  
  8. }  
代码 10.10 带有工厂方法的工厂对象

这些工厂方法使得改变类Element的实现通过使用elem工厂方法实现而不用显式地创建新的ArrayElement实例成为可能。为了不使用单例对象的名称,Element,认证而调用工厂方法,我们将在源文件顶上引用Element.elem。换句话说,代之以在Element类内部使用Element.elem调用工厂方法,我们将引用Element.elem,这样我们只要使用它们的简化名,elem,就可以调用工厂方法。代码10.11展示了类Element在这些改变之后的样子。

  1. import Element.elem  
  2. abstract class Element {  
  3. def contents: Array[String]  
  4. def width: Int =  
  5. if (height == 00 else contents(0).length  
  6. def height: Int = contents.length  
  7. def above(that: Element): Element =  
  8. elem(this.contents ++ that.contents)  
  9. def beside(that: Element): Element =  
  10. elem(  
  11. for (  
  12. (line1, line2) < - this.contents zip that.contents  
  13. ) yield line1 + line2  
  14. )  
  15. override def toString = contents mkString "\n" 
  16. }  
代码 10.11 重构以使用工厂方法的类Element

而且,有了工厂方法之后,子类ArrayElement,LineElement和UniformElement现在可以是私有的,因为它们不再需要直接被客户访问。Scala里,你可以在类和单例对象中定义其它的类和单例对象。因此一种让Element的子类私有化的方式就是把它们放在Element单例对象中并在那里声明它们为私有。需要的时候,这些类将仍然能被三个elem工厂方法访问。代码10.12展示了其中的细节。

  1. object Element {  
  2.  private class ArrayElement(  
  3.   val contents: Array[String]  
  4.  ) extends Element  
  5.  private class LineElement(s: String) extends Element {  
  6.   val contents = Array(s)  
  7.   override def width = s.length  
  8.   override def height = 1 
  9.  }  
  10.  private class UniformElement(  
  11.   ch: Char,  
  12.   override val width: Int,  
  13.   override val height: Int  
  14.  ) extends Element {  
  15.   private val line = ch.toString * width  
  16.   def contents = Array.make(height, line)  
  17.  }  
  18.  def elem(contents: Array[String]): Element =  
  19.   new ArrayElement(contents)  
  20.  def elem(chr: Char, width: Int, height: Int): Element =  
  21.   new UniformElement(chr, width, height)  
  22.  def elem(line: String): Element =  
  23.   new LineElement(line)  
  24. }  

代码 10.12 用私有类隐藏实现

【相关阅读】

  1. 如何实现Scala的above,beside和toString
  2. Scala学习:使用组合与继承
  3. 在Scala中定义final成员
  4. Scala程序中如何实现多态和动态绑定
  5. Scala学习:调用超类构造器和override修饰符的使用

责任编辑:book05 来源: Artima
相关推荐

2009-07-20 16:56:51

Scala类的定义

2009-07-21 12:18:37

ScalaRational对象toString

2009-07-21 08:21:46

Scala对象相等性

2014-05-22 10:13:24

云办公锐捷网络

2009-11-16 17:04:46

Inside Scal

2009-07-21 16:58:31

Scala变量范围

2009-07-22 07:43:00

Scala闭包

2009-07-21 17:21:57

Scala定义函数

2021-10-25 12:00:16

智能建筑物联网

2009-09-09 11:14:16

Scala对象

2009-07-08 15:35:18

Case类Scala

2009-07-22 07:57:00

ScalaCurry化函数

2010-11-17 11:31:22

Scala基础面向对象Scala

2012-06-28 09:40:04

惠普工作站HP Z620

2009-08-03 11:07:18

Scala Actor

2011-06-28 11:06:16

Scala

2009-06-22 14:26:12

ScalaXML对象

2010-03-11 10:34:22

Scala

2009-07-22 08:57:49

Scalafinal
点赞
收藏

51CTO技术栈公众号