[Scala] java.lang.Dateクラスの最も小さなオブジェクトEarlyTimeを定義する
今日は、Javaのオブジェクトを継承して、Scalaのシングルトンオブジェクトを作成してみます。題材は、RakeのEarlyTimeクラスを使ってみます。
EarlyTimeクラスはすべてのDateオブジェクトの中でもっとも小さいオブジェクトで、どんな小さなDateオブジェクトと比較しても必ず小さくなるシングルトンのValueObjectです。
まず、java.lang.Dateを継承して、Scalaのシングルトンを作成します。
import java.util.Date object EarlyTime extends Date { override def compareTo(other:Date) = {-1} override def toString = {"<EARLY TIME>"} }
次に、DateクラスのcompareToを拡張するMixinを定義します。
trait DateMixin extends Date { override def compareTo(other:Date) = { if (EarlyTime == other) { -(other.compareTo(this)) } else { super.compareTo(other) } } }
DateMixinでは、compareToメソッドをオーバーライドし、EaryTimeオブジェクトを引数に取るときに、EarlyTimeオブジェクトのcompareTo演算子を呼び出します。また、EarlyTimeオブジェクトと異なる場合には、元のDateオブジェクトのcompareToを呼び出します。
では、実際に評価してみます。
scala> EarlyTime.compareTo(new Date(java.lang.Long.MIN_VALUE)) res1: Int = -1 scala> EarlyTime.compareTo(new Date(java.lang.Long.MAX_VALUE)) res2: Int = -1 scala> scala> (new Date with DateMixin).compareTo(EarlyTime) res3: Int = 1 scala> (new Date(0) with DateMixin).compareTo(EarlyTime) res4: Int = 1 scala> (new Date(java.lang.Long.MIN_VALUE) with DateMixin).compareTo(EarlyTime) res5: Int = 1
確かにEarlyTimeは常に小さいオブジェクトになっています。
これだとDateクラスの宣言が使いにくいので、companionオブジェクトを定義します。Scalaではclassと同名のobjectをcompanionオブジェクトと呼び、クラス生成時の便利メソッドを提供する仕組みを用意しています。たとえば、
scala> List(1,2,3) res1: List[Int] = List(1, 2, 3)
なんかもcompanionオブジェクトだったりします。
では、applyメソッドを持つDate companionオブジェクトを定義してみましょう。
object Date { def apply(xs: java.lang.Long) : Date = { new Date(xs.longValue()) with DateMixin } def apply():Date = { new Date() with DateMixin } }
java.lang.Longを引数にとるapplyメソッドと、引数なしのapplyメソッドを定義しました。このapplyメソッドは一致する型のメソッドが暗黙的に呼び出されます。
scala> Date(1L) res18: java.util.Date = Thu Jan 01 09:00:00 JST 1970 scala> Date() res19: java.util.Date = Sat Apr 11 11:53:04 JST 2009
最後にListでソートしてみましょう。
scala> List(Date(0L), Date(2000L) , EarlyTime, Date() ).sort((e1,e2) => (e1 compareTo e2) > 0) list: List[java.util.Date] = List(Sat Apr 11 11:53:43 JST 2009, Thu Jan 01 09:00:02 JST 1970, Thu Jan 01 09:00:00 JST 1970, <EARLY TIME>)
正しくソートされましたね。
今日は、java.lang.Dateクラスを拡張し、ScalaのEarlyTimeクラスを定義してみましたがいかがでしょう?なんとなくScalaの拡張性の高さが伺えるサンプルとなったのではないでしょうか?