資料封裝的達成方式,通常就是透過 access control來達成。
所謂「access control」就是在定義 class 時,你希望該 class 有多少資訊可以給外界使用。
access control 有時又會稱呼為「visibility」。
Java 的 access control 有 4 種
1. private:只有自己可以用
2. package:只有自己與同 package 的可以用,這是 default
3. protected:只有自己、同 package、以及 subclass 可以用4. public:全世界都可用
Java 使用 modifier 來定義 method 與 data field 的 access control。Java access modifier 有 public、protected、private。並沒有 package 這種 modifier,但 default 是 package access。
Java 的 access control 相信大家都熟,所以不仔細介紹。
Scala 的 access control,大部分的概念與 Java 相同,也同樣使用 access modifier 來定義 access control,但有些地方不一樣。以下依序說明:
1. Scala 標榜快速開發,所以 default 是 public。只有那些你想要保護的 method 或 data field,你才需要使用 access modifier 加以保護。
2. Scala 的 access modifier 只有 private 與 protected,沒有 public。也沒有所謂的「package access」這種模式,因為沒有標明 access modifier,就表示是 public。但並不表示 Scala 無法做到「只讓相同 package 的 class 來 access」,Scala 使用「protection scope」來達到,protection scope 將詳述於下。
3.Private member:outer class 不能 access inner class 的 private field。
Java 把 inner class 當成與自己是同一個體,所以 inner class 與 outer class 彼此可以互相 access 對方的 private field。
舉例說明
class J { private int n_outer_private; //宣告一個 private data field class Inner { private int n_inner_private; void p() { int n = n_outer_private; //可以使用 outer private field } } void p_outer() { Inner inner = new Inner(); int n = inner.n_inner_private; //可以使用 inner private field } }但 Scala 對待 private 的方式,比 Java 更加嚴謹。Scala 為支援 functional 與 concurrency 的因素,決定將 改變 Java 那種把 outer class 與 inner class 視為同一個體的觀念。
在 Scala 中,inner class 視為 implement 的手段,所以 inner class 會被保護起來。outer class 無法 access inner class 的 private field。但 inner class 仍然視為 outer class 的一員,仍舊可以 access outer 的 private field。
範例:outer class 不可 access inner class 的 private。但 inner class 可以 access outer class 的 private。
class S { private var n_outer_private = 10 class Inner { private var n_inner_private = 10 def inner_print = println(n_outer_private) // 這裡是 inner class 去 access outer class 的 private,這理是正確的 } def outer_print = { val inner = new Inner val n = inner.n_inner_private // 這裡是 outer class 去 access inner 的 private,這裡會有 compile 錯誤 } }
4.Protected field 只有自己與 subclass 可以 access,移除 package 可以 access 的觀念。
在 Java,protected field 可以讓相同 package 的其他 class 來 access。但這個許可,在 Scala 被移除,所以 Scala 的 protected 只有自己與 subclass 可以 access。
同樣的,若希望 package 的其他 class 可以 access 被保護起來的 field,可以使用「protection scope」的方式來做到。
範例
class S1 { protected def p_protected() = println("S1") } class S11 extends S1 { def p_S11 = p_protected() // 使用 super class 的 protected,這是合法的 } class S2 { val s1 = new S1 def p_S2 = s1.p_protected() // 使用同一 package 的 protected,在 Scala 這是不合法的。但在 Java 這是合法的 }
5. Protection Scope:private 或是 protected 保護的 field,可以進一步訂定保護的範圍。
所謂保護的範圍,指的是我們可以擴充或縮小可以 access 的範圍。
比如 private 的 access 範圍,原來指的是自己的 class,但我們可以使用「protection scope」加以擴充或縮小。
格式為:
private[X] field 或
protected[X] field
private[X] field 代表設定該 field 為 private,但可以放大或縮小到 X 的範圍。
protected[X] field 代表設定該 field 為 protected,但可以放大或縮小到 X 的範圍。
這個[X]稱為 access qualifier,X 可以縮小為 this,或是放大到 package。所以我們可以用這個方式來定義,package private 或 package protected。
範例:限定範圍到 package
package p1 { package p2 { private[p1] class C1 // class C1 為 private,且可以 access 的範圍擴充到 package p1 private[p2] class C2 // class C2 為 private,且可以 access 的範圍擴充到 package p1.p2 } }範例:限定範圍到 outer class
class Outer { class Inner { protected[Outer] def p1 = println("p1") // 限定的範圍擴充到 Outer } }範例:限定範圍到 class
class Outer { class Inner { protected[Outer] def p1 = println("p1") // 限定的範圍擴充到 Outer } }範例:限定範圍到自己這個 instance。
這是 Java 沒有的限制方式,表示本 field,只有自己 instance 可以 access,就算相同的 class 的 instance 也不允許 access。此種限制方式稱為「object-private」,是最嚴格的限制
class S { private[this] val n_object_private = 10 // 這個是 object private def p = { val s = new S // create 另一個 S instance val n = s.n_object_private // 錯誤,因為在本 method 底下,不允許 access 別的 instance 的 object private field } }
6. Companion object 與 class 的 access right。
Companion object 與 class 這兩個東西,在 Java 世界中其實是一個 class,為了簡化方便,Scala 將一個 class 創造出兩個 class 出來。
既然原先在 Java 中本來是一個 class,所以二者本來就是一體,所以有兩個結論
a. Companion object 與 companion class 彼此可以互相 access private 的部份。
b. Companion object 與 companion class 的 access right 是一致的。也就是,若有一個 class X 允許讓 class C access,則 object C 同樣也 access X。
7. Package 沒有 access control 的機制,也就是 package 一定都是 public 的。
8. class 宣告也可以加上 private 或 protected 以做進一步的控制。
protected 的 class 表示該 class 只能給同一個 package 或 sub_package 的其他 class access。
private 的 class 表示該 class 只能給同一個 package 的其他 class access。
protected[this] 的 class 表示該 class 只能給包起來的 package 的其他 class access。
private[this] 的 class 表示該 class 只能給包起來的 package 的其他 class access。
範例
package p { private class C { // 宣告 package p 裡面有一個 private class C } }
沒有留言:
張貼留言