LL脳がscalaの勉強を始めたよ その6
4章の後半の前半:シングルトンオブジェクト
Web上のScala情報サイトを見ているとクラス定義の際にclassとobjectが同時に定義されていることが多いんだけども、その実態についての説明ー
今回も理解がおっつかないので後半全部は無理でしたー、のダメ分割デス
シングルトンオブジェクト
javaなんかと違ってScalaは静的メンバーが持てないので代わりにシングルトンオブジェクトを持っている…とのこと
そもそも静的メンバーって何よ?と思ったので調べてみると
静的メンバは、クラスに対してstatic定義された変数やメソッド。メンバーを呼び出すのにインスタンス化の必要はない。静的メンバの呼び方は次のようにnewする必要なし。 // 静的変数 クラス名.変数名; // 静的メソッド クラス名.メソッド名(引数);
静的メンバは複数呼び出してもアドレスは共通らしいので、グローバルみたいな扱いをするって解釈でいいのかしら?静的メンバーはオブジェクトを持たないらしいので、純粋なオブジェクト指向からは外れる存在らしい。
そこで、Scalaは完全なオブジェクト指向だから静的メンバーは持たない、代わりにシングルトンオブジェクトを用意するぜ!野郎ども!とのこと。
とりあえず実感を得るために例を書いてみる
前回定義した掛け算をするクラスに対応するシングルトンオブジェクトを書いてみる。
動きとしては引数をわたすことでHogeクラスを利用した掛け算を行って結果をキャッシュして、前回と同様の引数が渡ってきたときはキャッシュ内容を返すものデス
/*** Hogeクラスの定義(前回定義した掛け算するクラス) ***/ class Hoge { var moge = 3 private var huga = 0 def add(i: Int) { huga += i} def multiple() = huga * moge } /*** Hogeシングルトンオブジェクトの定義 ***/ // 可変長のmutableなMapが必要なのでインポート import scala.collection.mutable.Map // オブジェクト定義 object Hoge { // キャッシュ用のマップを定義 private val cache = Map[Int, Int]() // Hogeクラスを利用した計算結果を返すメソッド def calc(i: Int): String = // 引数が以前計算した値であればキャッシュした内容を返す if(cache.contains(i)) // キャッシュ内容を返す "cached value: " + cache(i).toString // キャッシュがなければ計算 else { // Hogeクラスを利用して計算 val h = new Hoge h.add(i) val result = h.multiple() // 計算結果をキャッシュに追加 cache += (i -> result) // 計算結果を返す "calc value: " + result.toString } }
上記のように対応したクラスとオブジェクトをそれぞれ、コンパニオンクラス・コンパニオンオブジェクトと呼ぶらしい。ちなみにコンパニオンクラスを持たないオブジェクトはスタンドアロンオブジェクトと呼ぶとのこと。
実行例
// 実行コード println(Hoge.calc(1)) println(Hoge.calc(2)) println(Hoge.calc(1)) // 実行結果 calc value: 3 calc value: 6 cached value: 3
シングルトンオブジェクトの特徴
何らかのコードから初めてアクセスされたときに自動的に初期化されるので、クラスのようにパラメータを渡すことができないのデス
多分間違っているであろう解釈、突っ込み大歓迎
コンパニオンオブジェクトはコンパニオンクラスを利用するための経路としての役割を担う。シングルトンなので(例のようなキャッシュなんかの)保持情報の保証もできるし…うん、激しく間違っている気がするけど使っていくうちに実感するに違いない。