Scala编程指南:面向对象编程

来源:java认证发布时间:2012-11-12 13:13:03java认证视频

    这里是ButtonWithCallbacks 的完整Specification(规格)的一部分,它展示了require 指令的作用。
    // code-examples/Traits/ui/button-callbacks-spec.scala package ui import org.specs._ object ButtonWithCallbacksSpec extends Specification {   "A ButtonWithCallbacks" should {     // …     "not be constructable with a null callback list" in {       val nullList:List[() => Unit] = null       val errorMessage =         "requirement failed: Callback list can't be null!"       (new ButtonWithCallbacks("button1", nullList)) must throwA(         new IllegalArgumentException(errorMessage))     }   } } Scala 甚至使得把null 作为第二个参数传给构造函数变得很困难;它不会再编译时做类型检查。然而,你向上面那样可以把null 赋给一个value。如果我们没有must throwA(…) 子句,我们会看到下面的异常被抛出。
    java.lang.IllegalArgumentException: requirement failed: Callback list can't be null!         at scala.Predef$.require(Predef.scala:112)         at ui.ButtonWithCallbacks.(button-callbacks.scala:7) … ButtonWithCallbacks 定义了两个方便用户使用的辅助构造函数。第一个辅助构造函数接受一个标签和一个单独的回调函数。它调用主构造函数,并且传递给它标签和包含了回调函数的新列表。
    第二个辅助构造函数只接受一个标签。它调用主构造函数,并且传入Nil(Nil 表示了一个空的List 对象)。然后构造函数打印出一条警告消息指明没有回调函数,因为列表是不可变的,所以我们没有机会用一个新的值来替代现有的回调函数列表。
    为了避免无限递归,Scala 要求每一个辅助构造函数调用在它之前定义的构造函数[ScalaSpec2009]。被调用的构造函数可以是另外一个辅助构造函数或者主构造函数,而且它必须出现在辅助构造函数主体的第一句。额外的过程可以在这个调用之后出现,比如我们例子中的打印出一个警告消息。
    注意
    因为所有的辅助构造函数最终都会调用主构造函数,它主体中进行的逻辑检查和其它初始化工作会在所有实例被创建的时候执行。
    Scala 对构造函数的约束有一些好处。
    消除重复
    因为辅助构造函数会调用主构造函数,潜在的重复构造逻辑就被大大地消除了。
    代码体积的减少
    正如例子中所示,当一个或更多的主构造函数参数被声明为val 或者var,Scala 会自动产生一个字段,合适的存取方法(除非它们被定义为private,私有的),以及实例被创建时的初始化逻辑。
    不过,这样也有至少一个缺点。
    缺少弹性
    有时候,迫使所有构造函数都是用同一个构造函数体并不方便。然而,我们发现这样的情况只是极少数。在这种情况下,可能是因为这个类负责了太多东西,而且应该被重构为更小的类。
    调用父类构造函数
    子类的主构造函数必须调用父类的一个构造函数,无论是主构造函数或者是辅助构造函数。在下面的例子里,类RadioButtonWithCallbacks 会继承ButtonWithCallbacks,并且调用ButtonWithCallbacks 的主构造函数。“Radio”按钮可以被设置为开或者关。
    // code-examples/BasicOOP/ui/radio-button-callbacks.scala package ui /** * Button with two states, on or off, like an old-style, * channel-selection button on a radio. */ class RadioButtonWithCallbacks(   var on: Boolean, label: String, clickedCallbacks: List[() => Unit])       extends ButtonWithCallbacks(label, clickedCallbacks) {   def this(on: Boolean, label: String, clickedCallback: () => Unit) =       this(on, label, List(clickedCallback))   def this(on: Boolean, label: String) = this(on, label, Nil) } RadioButtonWithCallbacks 的主构造函数接受3个参数,一个开关状态(真或假),一个标签,以及一个回调函数例表。它把标签和回调函数列表传给父类ButtonWithCallbacks。开关状态参数(on)被声明为var,所以是可变的。on 也是每一个单选按钮的私有属性。 为了和父类保持统一,RadioButtonWithCallbacks 还定义了两个辅助构造函数。注意它们必须调用一个之前定义的构造函数,和之前一样。它们不能直接调用ButtonWithCallbacks 的构造函数。为所有类声明这些构造函数可能是乏味的,但是我们在《第4章 - Traits》中探索的技巧可以帮助我们减少这样的重复。
    注意
    虽然和Java 一样,super 关键字通常被用来调用重写的方法,但是它不能被用作调用父类的构造函数。
    嵌套类
    Scala 和许多面向对象语言一样,允许你嵌套声明类。假设我们希望所有的部件都有一系列的属性。这些属性可以是大小,颜色,是否可见等。我们可以使用一个简单的map 来保存这些属性,但是我们假设还希望能够控制对这些属性的存取,并且当它们改变时能进行一些其它的操作。
    下面的例子展示了我们如何利用从《第4章 - Traits》中的“混合Traits”章节学到的特性来扩展我们原来的Widget 例子。
    // code-examples/BasicOOP/ui/widget.scala package ui abstract class Widget {   class Properties {     import scala.collection.immutable.HashMap     private var values: Map[String, Any] = new HashMap     def size = values.size     def get(key: String) = values.get(key)     def update(key: String, value: Any) = {       // Do some preprocessing, e.g., filtering.       valuesvalues = values.update(key, value)       // Do some postprocessing.     }   }   val properties = new Properties }     我们添加了一个Properties 类,包含了一个私有的,可变的HashMap (HashMap 本身不可变)引用。我们同时加入了3个公有方法来获取大小(例如,定义的属性个数),获取map 中的元素,以及更新map 中对应的元素等。我们可能需要在update 方法上做更多的工作,已经用注释标明。
    注意
    你可以从上面的例子中看到,Scala 允许在一个类中定义另外一个,或者成为“嵌套”。当你有足够多的功能需要归并到一个类里,并且这个类在仅会被外层类所使用时,一个嵌套类就非常有用。
    到这里为止,我们学习了如何声明一个类,如何初始化它们,以及继承的一些基础。在下一个章节,我们会讨论类和对象内部的可见性规则。

    编辑特别推荐:

    Java读取文件内容再编辑

    JS获取单选与多选按纽的值

    每一种文件类型所对应的ContentType

视频学习

我考网版权与免责声明

① 凡本网注明稿件来源为"原创"的所有文字、图片和音视频稿件,版权均属本网所有。任何媒体、网站或个人转载、链接转贴或以其他方式复制发表时必须注明"稿件来源:我考网",违者本网将依法追究责任;

② 本网部分稿件来源于网络,任何单位或个人认为我考网发布的内容可能涉嫌侵犯其合法权益,应该及时向我考网书面反馈,并提供身份证明、权属证明及详细侵权情况证明,我考网在收到上述法律文件后,将会尽快移除被控侵权内容。

最近更新

社区交流

考试问答