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.