Javaは「抽象クラス」で実装を上手に再利用できる【改訂版】Eclipseではじめるプログラミング(15)(2/3 ページ)

» 2010年03月30日 00時00分 公開
[小山博史株式会社ガリレオ]

起動するクラスを作成して実行

 では、これを起動するクラスAppを次のように作成して、実行してみましょう。実行画面に「SimpleConcreteClass」と表示されるはずです。

 ちなみに、抽象クラスは実装が完成していませんから、new演算子でインスタンスを生成できません。

package sample15.simple;
  
public class App {
    public static void main(String[] args) {
        SimpleConcreteClass app = new SimpleConcreteClass();
        app.simpleMethod();
        // 次の行はコメントを外すと、エラーとなる
        // SimpleAbstractClass a = new SimpleAbstractClass();
  }
}
sample15/simple/App.java
SimpleConcreteClass
App.javaの実行結果

 抽象クラスの基本的な文法事項は以上です。次は、これがどういう場合に便利なのかについて考えてみましょう。

JavaのAPIで「抽象クラスが、なぜ便利なのか」をひも解く

抽象クラスの例「java.text.Format」

 JavaのAPIで用意されている抽象クラスの例としては、「java.text.Format」クラスがあります。このクラスは、「日付け、メッセージ、数字などの値を決まった書式に従った文字列に変換する」機能を提供するために用意されています。

 例えば、「2010年3月10日」を「2010/03/10」と表示するようにしたい、つまり、「日付けで年は4けた、月日は2けた、各けたで0の値も表示して、区切りはスラッシュ(/)にしたいこと」があります。そんな場合に、このクラスが利用できます。これを使ってみましょう。

 java.text.FormatのAPIドキュメントを見ると分かりますが、このクラスはformat()メソッドとparseObject()メソッドに、abstractが付いています。この2つが抽象メソッドとして用意されているわけです。このことから、このほかのメソッドについては、実装が提供されていることが分かります。

「java.text.Format」のサブクラス「java.text.DateFormat」

 このクラスをextendsしたクラスとして、「java.text.DateFormat」クラスがあります。「日付けを、ある書式に従った文字列へ変換する基本的な機能」を、このクラスが実装しています。java.text.DateFormatのAPIドキュメントを確認すると分かりますが、このクラスではjava.text.Formatの抽象メソッド(format()メソッド、parseObject()メソッド)を実装したり、日付けを扱うのに便利なformat(java.util.Date date)メソッドなども追加で実装しています。

 ただし、一部のメソッドについては、抽象メソッドとなっていて、java.text.DateFormatクラスは抽象クラスとして用意されています。このため、このクラスをextendsして、抽象メソッドを実装するクラスを用意する必要があります。

「java.text.Format」の具象クラス「java.text.SimpleDateFormat」

 java.text.DateFormatは抽象クラスであるため、これをそのまま使って「日付けをある書式に従った文字列へ変換する」ということはできません。しかし、心配はありません。

 Javaでは、きちんとjava.text.DateFormatクラスの具象クラスを用意していて、「java.text.SimpleDateFormat」クラスというものがあります。このクラスのAPIドキュメントを見ると、abstractが付いたメソッドはありません。

「java.text.SimpleDateFormat」の使い方

 それでは使い方を見てみましょう。ここでは、先ほどの例のように日付けを表示するプログラムとして、次の「sample15.dateformat.App」クラスを作成してください。プログラムを実行したときの日付けを表示するようにしています。

package sample15.dateformat;
  
public class App {
    public static void main(String[] args) {
        java.text.Format f = new java.text.SimpleDateFormat("yyyy/MM/dd");
        System.out.println(f.format(new java.util.Date()));
    }
}
sample15/dateformat/App.java
2010/03/22
App.javaの実行結果例

 変数の型としてはjava.text.Formatを指定します。しかし、抽象クラスはインスタンスを生成できませんから、SimpleDateFormatクラスのインスタンスを生成して、これを参照するようにします。SimpleDateFormatのコンストラクタとしては「SimpleDateFormat(String pattern) 」を使っています。

 patternには、「日付けと時刻のフォーマットを記述するパターン」を指定することになっていて、ここでは「yyyy/MM/dd」を指定しています。yが年、Mが月、dが日を表現しています。パターンにどんな値が使えるかはAPIドキュメントを見て確認してください。

 使い方は至って単純で、format()メソッドを呼び出しているだけです。引数には「new java.util.Date()」として「java.util.Date」クラスのインスタンスを生成して渡しています。このようにすることで、現在時刻表すDateオブジェクトをformat()メソッドへ渡しているのです。

 以上のとおり、抽象度の高いクラス順に、java.text.Format、java.text.DateFormat、java.text.SimpleDateFormatといったクラスがJavaでは用意されていて、開発者の要望に応じて、利用するクラスを選択できるようになっています。

 今回は、とにかく実装を行うために、java.text.SimpleDateFormatを選びましたが、何らかの機能強化をしたい場合は、java.text.DateFormatやjava.text.Formatを使って、実装されていない抽象メソッドを独自に実装するという道もあります。

もうちょっと複雑な例で抽象クラスの理解を深める

 オブジェクト指向プログラミングにおいて、基本設計時にはクラスの役割を考えます。その際、「ほかのクラスへどのようなインターフェイスを提供するかを決める」ことが重要です。次に、共通のインターフェイスを持つ複数のクラスがある場合は、それらが共通の実装を持てるのであれば抽象クラスで実装しておき、持てない分については、各クラスが独自に実装します。

 ここでは、抽象クラスについて、もう少し理解を深めるために、フォーマット文字列を保持する抽象クラスを用意し、そこへフォーマット機能を追加してみましょう。

日付けフォーマットを保持する抽象クラスを用意る

 まず、次のような簡単な抽象クラスを用意しましょう。このクラスは、フォーマット文字列を保持するためにformatStringフィールドを持ち、そのフィールドへのアクセサメソッドを持ちます。指定された書式に文字列を変換するメソッドとしてformat()メソッドを用意しますが、これは抽象メソッドとして宣言します。

package sample15.dateformatter;
  
import java.util.Calendar;
  
public abstract class DateFormatter {
    private String formatString = "";
    public void setFormatString(String formatString) {
        this.formatString = formatString;
    }
    public String getFormatString() {
        return formatString;
    }
    public abstract String format(Calendar c);
}
sample15/dateformatter/DateFormatter.java

 なお、複雑な日付けフォーマット出力を実現するには、先ほどのjava.text.SimpleDateFormatクラスが使えます。また、「java.util.Formatter」というクラスも利用できます。

「暦」を表す「java.util.Calendar」クラス

 Dateクラスは「特定の時点」を表すのに対して、「java.util.Calendar」クラスは「暦」を表します。英語圏では月は「Jan.」「Feb.」といった文字列で表すことが多いですが、日本では「一月」「二月」といった文字列で表すことが多いので、こういった表現を扱いたいときは、「java.util.Calendar」クラスを使うことになります。

 ですから、ここではformat()メソッドのパラメータとしてCalendarクラスを使うことにしました。このクラスは、java.utilパッケージに含まれています。

java.text.SimpleDateFormatを使った具象クラス

 java.text.SimpleDateFormatを使って実装すると、次のようなクラスになります。SimpleDateFormatの場合は、Dateオブジェクトをformat()メソッドに渡す必要があるので、「new Date(c.getTimeInMillis())」としています。

package sample15.dateformatter;
  
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
  
public class DateFormatterImpl1 extends DateFormatter {
  
    @Override
    public String format(Calendar c) {
        SimpleDateFormat df = new SimpleDateFormat(getFormatString());
        return df.format(new Date(c.getTimeInMillis()));
    }
}
sample15/dateformatter/DateFormatterImpl1.java

 CalendarクラスのgetTimeInMillis()メソッドは、そのCalendarオブジェクトが保持している時刻のミリ秒をlong型で表して返すメソッドです。これを使ってDateオブジェクトを初期化しています。

 java.text.SimpleDateFormatの代わりにjava.util.Formatterを使って実装すると、次ページのようなクラスになります。

Copyright © ITmedia, Inc. All Rights Reserved.

RSSについて

アイティメディアIDについて

メールマガジン登録

@ITのメールマガジンは、 もちろん、すべて無料です。ぜひメールマガジンをご購読ください。