java.util.Formatterを使った具象クラスは次のようになります。
package sample15.dateformatter;
import java.util.Calendar;
import java.util.Formatter;
public class DateFormatterImpl2 extends DateFormatter {
private StringBuilder sb = new StringBuilder();
private Formatter formatter = new Formatter(sb);
@Override
public String format(Calendar c) {
sb.delete(0, sb.length());
formatter.format(getFormatString(), c);
return sb.toString();
}
}
java.util.Formatterを使う場合は、StringBuilderの領域をコンストラクタに渡す必要があります。この領域を使って、Formatterクラスは文字列を指定された書式へ変換します。
このため、再利用するには「sb.delete(0, sb.length());」のように領域をクリアする必要があります。書式指定については、SimpleDateFormatクラスとは別で「%1$tY/%1$tm/%1$td」のような指定が必要です。
ここでは詳細は説明しませんが、次の例では、「%1」はCalendarオブジェクト「c」を参照すること、「t」は時刻形式にすることを意味します。「Y」は年、「m」は月、「d」は日、といった意味を持っています。詳細は、FormatterクラスのAPIドキュメントを参照してください。
DateFormatterImpl1クラスと、DateFormatterImpl2クラスという具象クラスを用意しました。このように具象クラスを用意することにより、SimpleDateFormatに慣れている開発者はDateFormatterImpl1クラスを、Formatterに慣れている開発者はDateFormatterImpl2クラスを使う、といった選択ができるようになります。
では、具象クラスの動作を確認するために、次のようなAppクラスを作成しましょう。日付けフォーマットの指定方法が利用しているクラスに応じて変わりますから、組み合わせを間違えないようにしましょう。
package sample15.dateformatter;
import java.util.Calendar;
public class App {
public static void main(String[] args) {
Calendar c = Calendar.getInstance();
DateFormatter df = new DateFormatterImpl1();
df.setFormatString("yyyy/MM/dd");
System.out.println(df.format(c));
df.setFormatString("yyyy/MM");
System.out.println(df.format(c));
df = new DateFormatterImpl2();
df.setFormatString("%1$tY/%1$tm/%1$td");
System.out.println(df.format(c));
df.setFormatString("%1$tY/%1$tm");
System.out.println(df.format(c));
}
}
2010/03/23 2010/03 2010/03/23 2010/03
DateFormatterImpl1クラスとDateFormatterImpl2クラスは、メソッドの互換性はありますが、書式の指定方法が異なる点には注意が必要です。
書式指定方法も互換性を持つようにしたい場合は、「yyyy/MM/dd」といったSimpleDateFormat用の書式文字列を解析して「%1$tY/%1$tm/%1$td」といったFormatter用の書式文字列へ変換する機能が必要です。
ここまで、抽象クラスについて説明をしましたが、理解できたでしょうか。インターフェイスを用意してから、複数の実装クラスを作成したときに、同じ処理を複数のクラスが持つようなら、抽象クラスを利用することで、共通の実装は抽象クラスでメンテナンスし、各クラス独自の処理については、それぞれのクラスに実装可能です。
また、java.text.Formatクラスやそのサブクラスを見ても分かるように、抽象度の高いクラスを用意しつつ、基本的な実装を持つクラスを用意することにより、開発者のさまざまなニーズに応えられます。カスタマイズしたクラスを作成したい開発者は、java.text.Formatクラスを直接extendsして独自クラスを作成できますし、手っ取り早く基本機能を持つクラスを利用したい開発者は、java.text.SimpleDateFormatのようなクラスをそのまま使えます。
ちょっとしたカスタマイズをしたいだけなら、java.text.DateFormatクラスが使えます。抽象クラスを利用することにより、開発者にとって、再利用しやすいクラスライブラリを開発できます。
既存のインターフェイスや実装クラスを利用して、効率良くシステム開発をしたい場合にも、抽象クラスをうまく利用すると、実現したい機能を取りあえず実装しておいて、後で差し替えができるようになります。機能もそれなりに実装されていて、なおかつ動くものを、急いで実装したい場合には役に立つはずです。
抽象クラス、インターフェイス、具象クラスの違いを理解して、効率良く開発できるようになりましょう。今回作ったサンプルのソースコードはこちらからダウンロードできます。
小山博史(こやま ひろし)
情報家電、コンピュータと教育の研究に従事する傍ら、オープンソースソフトウェア、Java技術の普及のための活動を行っている。長野県の地域コミュニティである、SSS(G)やbugs(J)の活動へも参加している。
著書に「基礎Java」(インプレス)、共著に「Javaコレクションフレームワーク」(ソフトバンククリエイティブ)、そのほかに雑誌執筆多数。
Copyright © ITmedia, Inc. All Rights Reserved.