日付の範囲クラスの作成(精度指定付き)-2
昨日のCalendarRangeを修正したバージョン。
switch-caseを使う代わりにenumにプロパティを持たせ、それを利用して初期化します。
(Effective-Java 2ndも出たことだし、と無理矢理ぎみに使ってみまんた)
// ベースは昨日の日記参照 // http://d.hatena.ne.jp/asc_gamefreak/20080609/1213016167 public class CalendarRange extends Range<Calendar> { // Scaleにクリアする精度と初期値を追加 public static enum Scale { YEAR(Calendar.MONTH, 0) // ,MONTH(Calendar.DAY_OF_MONTH, 1) // ,DAY(Calendar.HOUR_OF_DAY, 0) // ,HOUR(Calendar.MINUTE, 0) // ,MINUTE(Calendar.SECOND, 0) // ,SECOND(Calendar.MILLISECOND, 0) // ,MILLISECOND(null, 0); private Integer clearScale; private int initValue; private Scale(Integer clearScale, int initValue) { this.clearScale = clearScale; this.initValue = initValue; } } // 省略... private static Calendar adjustScale(Calendar original, Scale scale) { if (scale == null) throw new NullPointerException("scale must not be null."); if (original == null) return null; Calendar cal = (Calendar) original.clone(); // switch-caseを使わずにScaleに渡したパラメータを使って初期化 for (Scale comparison : Scale.values()) { if (scale.ordinal() <= comparison.ordinal() && comparison.clearScale != null) { cal.set(comparison.clearScale, comparison.initValue); } } return cal; }
Enum#ordinal()メソッドは、定数を宣言した順に0起算の整数値を返してくれます。逆に言うと定数の定義順に依存して変ってしまう値なので、プログラマが定数に明確な順序を表す整数値を定義したいなら、ちゃんと専用のプロパティを用意してあげたほうが堅牢なコードになります。
// #ordinal() は定義順に依存する enum Scale1 { YEAR // YEAR. ordinal() => 0 ,MONTH // MONTH.ordinal() => 1 ,DAY; // DAY. ordinal() => 2 } enum Scale2 { MONTH // MONTH.ordinal() => 0 ,YEAR // YEAR. ordinal() => 1 ,DAY; // DAY. ordinal() => 2 } // こっちのほうがプログラマが明確に順序を定義できる enum Scale { YEAR(0) ,MONTH(1) ,DAY(2); private final int order; private Scale(int order) { this.order = order; }
というわけで今回のCalendarRangeも、本当のところはordinal()を使うのではなく個別にオーダー値を振ったほうが確実です。面倒なのでサボりましたが。
書くだけ書いてみたものの、昨日のswitch-caseのほうがよっぽど直感的な気がしました。
if(scale.ordinal() <= comparison.ordinal() ... とか何が言いたいんだかわからないコードです。