object PropSample { def main(args: Array[String]) : Unit = { val d : Data = new Data(100); println(d.value); d.value = 200; println(d.value); } } class Data(var value : Int)
100 200
クラス定義はこの一行で、public なメンバ変数 x の定義( Scala では、可視性修飾子がない場合は public )と、コンストラクターによる初期化が自動的に定義されている。
この時、内部的には private なフィールドと名前 x のアクセッサが生成されているのだが、Scala 的に見た場合には public メンバ変数へ直接アクセスしているということになる。
val 定義による更新の抑制
一般的にメンバ変数の公開による直接的なアクセスが禁忌とされるのは次の2つが主な理由である。
- 更新操作の防止ができない
- 参照/更新時のフックができない
前者に対しては、メンバ変数の定義を val にすれば更新操作を抑制することができる。
class Data(val value : Int)
こうすることで「 d.value = 200; 」に対しては「reassignment to val」とコンパイルエラーが発生する。
getter/setter の定義
何らかのフックをしたい場合には、フィールドを private にして setter と getter を明示的に定義することになる。
object PropSample { def main(args: Array[String]) : Unit = { val d : Data = new Data(100); println(d.value); d.value = 200; println(d.value); } } class Data(private var value_ : Int) { def value : Int = value_; def value_=(newValue : Int) = value_ = newValue; }
100 200
private 化したフィールドは名称を変えて、getter は公開されていた時のフィールド名で定義する。
次に setter は、Scala では 「 _= で終わるメソッドは _= を除いた部分に対する代入文として呼び出せる」 という見るからに胡散臭いルールがあるのでそれを使う。
ここで注目するべきところは、Data クラスの定義が setter/getter を使う形式に変更されたにもかかわらず、呼び出し側は最初のコードと全く変わっていないという点。
つまり、public なメンバ変数を作って実装しておいて、あとから必要になったデータクラスだけこっそり setter/getter 形式に変更することができる。
これは大きなアドバンテージだと思う。
Bean形式の setter/getter
何らかの事情で、getXXX、setXXX 形式のアクセッサが必要になることもあるかもしれない。
そんな時には、フィールドに「 @BeanProperty 」をつけることで getXXX、setXXX 形式のgetter / setter が自動生成される。
object PropSample { def main(args: Array[String]) : Unit = { val d : DataBean = new DataBean(100); println(d.getValue); d.setValue(200); println(d.getValue); } } class DataBean( @BeanProperty var value : Int)
「 @BooleanBeanProperty 」の場合は、getter が isXXX 形式になる。
「 @BeanProperty 」は getXXX / setXXX を追加しているだけなので、もとの「d.value」、「d.value = XXX」形式でもアクセスできることに注意。
これを阻止しようとして「@BeanProperty private var value : Int」とすると、 生成される getXXX / setXXX も private になってしまう。惜しい。
0 件のコメント:
コメントを投稿