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

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

   为了方便,我们会使用通用的“类型” 这一词语来指代类和Trait,对应的还有成员类型。除非特别声明,否则我们在使用通用术语“成员” 时会包含这些定义。
    大多数面向对象语言都有控制类型或者类型成员可见性(作用域)声明的结构。这些结构支持面向对象式的封装,即本质上只有类或者Trait 的公共抽象会被暴露出来,内部实现则被隐藏于视界之下。
    对于你的类、对象的用户所希望看到和使用的任何地方你都会想用公共可见性。但是记住,公共可见成员的集合构成了类型暴露出的抽象接口,包括类型的名字。
    面向对象设计世界的传统智慧是,字段应该为私有(private)或者受保护的(protected)。如果有存取需求,也应该通过方法来完成,而不是使得所有东西都默认可存取。统一访问原则(参见章节“当存取方法和字段无法区分时:统一访问原则”)归根结底是说我们可以通过方法或字段的直接存取给予用户公共(public)字段的访问语意,只要它对于任务来说是合适的即可。
    提示
    好的面向对象设计的艺术在于定义最小的,清晰的,有凝聚力的公共抽象层。
    类型有两种“用户”: 继承类型,以及使用类型实例的代码。继承类型通常比实例用户需要更多地存取父类型的成员。
    Scala 的可见性规则和Java 类似,但是倾向于更统一和灵活。例如,在Java 中,如果一个内部类有一个私有成员,则包含它的外部类是能看到的。在Scala 里,则不能看到,但是Scala 提供了另外一种方式来声明它对于包含它的外部类可见。
    和Java,C# 一样,修改可见性的关键字,比如private 和protected,在声明的最开始出现。你会在class,trait 关键字前,val 或者var 前,以及方法的def 前发现它们。
    注意
    你也可以在类的主构造函数前使用一个可见性修饰符。如果有,把它放在类型名称和类型参数后,参数列表之前。像这样:
    class Restricted[+A] private (name: String) {…}   表格 5.1,“可见域” 总结了可见性的范围。
    表格 5.1,可见域 名称 关键字 描述
    public 没有 public 成员在任何地方都可见,跨越所有边界
    protected protected protected 成员对于定义它的类型,继承类型以及嵌套类型可见,protected 类型仅在同一个包,子包中可见。
    private private private 成员对于定义它的类型和嵌套类型可见,private 类型仅在同一个包可见。
    scoped protected protected[scoped] 可见性被限制在域scoped 中,它可以是包,类型,或者this(对于成员来说就是该实例,对于类型来说就是它存在的包。参见下面的文字获取更多信息。
    scoped private private[scoped]  和scoped protected 一样,除了继承的时候。(下面会讨论)
    让我们来仔细探索一下这些可见性选项。为了简单,我们会使用字段来作为成员的例子。方法,类型声明的行为和字段是一致的。
    注意
    不幸的是,你不能对包做任何可见性修饰。因此,一个包永远都是public,即使它没有包含任何public 类型。
    Public 可见性
    任何没有显式可见性关键字的声明都是“public”,意味着它在任何地方都可见。在Scala 里没有public 关键字。这和Java 恰恰相反,Java 的默认行为是只在当前包里默认是public 可见性(也就是包私有的-“package private”)。其它面向对象语言,比如Ruby,也是默认public 可见性。
    // code-examples/BasicOOP/scoping/public.scala  package scopeA {    class PublicClass1 {      val publicField = 1     class Nested {        val nestedField = 1     }      val nested = new Nested    }    class PublicClass2 extends PublicClass1 {      val field2  = publicField + 1      val nField2 = new Nested()。nestedField    }  }  package scopeB {    class PublicClass1B extends scopeA.PublicClass1    class UsingClass(val publicClass: scopeA.PublicClass1) {      def method = "UsingClass:" +        " field: " + publicClass.publicField +        " nested field: " + publicClass.nested.nestedField    }  }   你可以用scalac 编译这个文件,应该不会遇到编译错误。
    这些包和类的任何成员都是public 的。主意,scopeB.UsingClass 可以访问scopeA.PublicClass1 和它的成员,包括嵌套类的实例以及它的public 字段。
    Protected 可见性
    Protected 可见性为实现继承的类型提供了一些好处,因为它需要对其父类型有更多的一些存取权限。任何用protected 关键字声明的成员只对定义它的类型,包括其实例和任何继承类型可见。当应用于类型时,protected 限制其可见性于包含它的package 中。
    J对比之下,Java 使得protected 成员对于整个包都可见。Scala 则用scoped (区域的)private 和protected 来控制这样的情况。
    // code-examples/BasicOOP/scoping/protected-wont-compile.scala  // WON'T COMPILE  package scopeA {    class ProtectedClass1(protected val protectedField1: Int) {      protected val protectedField2 = 1     def equalFields(other: ProtectedClass1) =        (protectedField1 == other.protectedField1) &&        (protectedField1 == other.protectedField1) &&        (nested == other.nested)      class Nested {        protected val nestedField = 1     }      protected val nested = new Nested    }    class ProtectedClass2 extends ProtectedClass1(1) {      val field1 = protectedField1     val field2 = protectedField2     val nField = new Nested()。nestedField  // ERROR    }    class ProtectedClass3 {      val protectedClass1 = new ProtectedClass1(1)      val protectedField1 = protectedClass1.protectedField1 // ERROR      val protectedField2 = protectedClass1.protectedField2 // ERROR      val protectedNField = protectedClass1.nested.nestedField // ERROR    }    protected class ProtectedClass4    class ProtectedClass5 extends ProtectedClass4    protected class ProtectedClass6 extends ProtectedClass4  }  package scopeB {    class ProtectedClass4B extends scopeA.ProtectedClass4 // ERROR  }   当你用scalac 编译这个文件的时候,你会得到下列输出。(为了配合排版,在N: 行号之前的文件名已经被移除。)
    16: error: value nestedField cannot be accessed in ProtectedClass2.this.Nested          val nField = new Nested()。nestedField                                    ^  20: error: value protectedField1 cannot be accessed in scopeA.ProtectedClass1          val protectedField1 = protectedClass1.protectedField1                                                ^  21: error: value protectedField2 cannot be accessed in scopeA.ProtectedClass1          val protectedField2 = protectedClass1.protectedField2                                                ^  22: error: value nested cannot be accessed in scopeA.ProtectedClass1          val protectedNField = protectedClass1.nested.nestedField                                                ^  32: error: class ProtectedClass4 cannot be accessed in package scopeA      class ProtectedClass4B extends scopeA.ProtectedClass4                                            ^  5 errors found   列表中的//ERROR 注释标识了无法解析的行。
    ProtectedClass2 可以存取ProtectedClass1 的protected 成员,因为它们是继承关系。然而,它不能存取protectedClass1.nested 的protected nestedField 字段。而且,ProtectedClass3 不能存取它使用的ProtectedClass1 实例的protected 成员。
    最终,因为ProtectedClass4 被声明为protected,它对于scopeB 包来说不可见。

    编辑特别推荐:

    Java读取文件内容再编辑

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

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

视频学习

我考网版权与免责声明

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

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

最近更新

社区交流

考试问答