XXXUtils の乱用をやめる - Calendar 編
標準のライブラリが使いにくいとき、つい XXXUtils のようなクラスを作ってしまいがちです。
例えば、悪名高き java.util.Calendar。来年の2月15日が何曜日か調べようと思ったら、次のようなコードを書かなければなりません。値の取得も設定も面倒で、なぜか月が0始まりになっています (歴史的な制約?)。
Calendar calendar = Calendar.getInstance(); calendar.add(Calendar.YEAR, 1); // 2月は month = 1 calendar.set(Calendar.MONTH, 1); calendar.set(Calendar.DAY_OF_MONTH, 15); // 文字列に変換する場合は、DateFormat を使用する。 DateFormat df = new SimpleDateFormat("EEEE"); String dayOfWeek = df.format(calendar.getTime()); System.out.println(dayOfWeek); // => 月曜日
まず、よくやる対策は CalendarUtils のようなクラスを作る方法です。
public class CalendarUtils { public static int getYear(Calendar calendar) { return calendar.get(Calendar.YEAR); } public static void addYears(Calendar calendar, int years) { calendar.add(Calendar.YEAR, years); } public static void setMonth(Calendar calendar, int month) { calendar.set(Calendar.MONTH, month - 1); } public static void setDay(Calendar calendar, int day) { calendar.set(Calendar.DAY_OF_MONTH, day); } public static String getDayOfYearText(Calendar calendar) { return new SimpleDateFormat("EEEE").format(calendar.getTime()); } }
CalendarUtils を使うと、先ほどのコードは次のように書けます。
Calendar calendar = Calendar.getInstance(); CalendarUtils.addYears(calendar, 1); // 2月は month = 2 CalendarUtils.setMonth(calendar, 2); CalendarUtils.setDay(calendar, 15); String dayOfWeek = CalendarUtils.getDayOfYearText(calendar); System.out.println(dayOfWeek); // => 月曜日
月が1始まりになり、コードも多少簡潔になりました。
この方法のメリットは、必要になったときに順次機能を追加できることです。
ただし、手続き的で、クラス名の装飾や、引数の calendar が冗長です。
そこで、最近はまっているのがラッパークラスを作る方法です。
Seasar2 付属の S2JDBC や、JavaScript ライブラリの jQuery でも採用されている方法です。
更新系のメソッドで this を戻り値で返しているのがミソです。
public class ISOCalendar { final Calendar calendar; public ISOCalendar() { this(Calendar.getInstance()); } public ISOCalendar(Calendar calendar) { this.calendar = calendar; } public ISOCalendar addYears(int years) { calendar.add(Calendar.YEAR, years); return this; } public ISOCalendar setMonth(int month) { calendar.set(Calendar.MONTH, month - 1); return this; } public ISOCalendar setDay(int day) { calendar.set(Calendar.DAY_OF_MONTH, day); return this; } public String getDayOfWeekText() { return new SimpleDateFormat("EEEE").format(calendar.getTime()); } }
このクラスを使うと、先ほどのコードがさらに簡潔になります。
String dayOfWeek = new ISOCalendar() .addYears(1) .setMonth(2) .setDay(15) .getDayOfWeekText(); System.out.println(dayOfWeek); // => 月曜日
IDE だと補間も効くので、ほんとサクサクコードが書けます。
この方法は、拡張が少し面倒なので、あらかじめある程度の機能を作りこんでおく必要があるのですが、一度作ってしまうと、開発がずいぶん楽になると思います。
というわけで、いま実際に作成している Calendar のラッパークラスです。
ISOCalendar.java
参考
- 流れるようなインターフェース - Martin Fowler's Bliki
http://capsctrl.que.jp/kdmsnr/wiki/bliki/?FluentInterface