カプセル化するとインスタンス変数は賢くなる:やり直し「JSPとTomcat」(8)
Javaを途中までかじったが挫折した。やはりJavaプログラマにスキルチェンジしたい! という読者のために、Tomcatの最新バージョンを使いながらJSPを基礎から解説していく。(編集部)
JavaBeansのプロパティとカプセル化
前回は、JavaBeansコンポーネントとして扱えるJavaクラスの条件として、以下の3つのルールを示しました。
- 引数なしのpublicコンストラクタでオブジェクトを生成できる
- 必要に応じて「プロパティ」「イベント」「メソッド」を備える
- 必要に応じて「Serializable」インターフェイスを実装する
今回は、これらのルールのうち、「プロパティ」とは何かを説明します。ちなみに、「イベント」および「メソッド」のルールは、主にJavaBeansをGUI開発に用いる場合に重要となるものであり、JSP開発などのサーバサイドで用いられることはほとんどありません。よって、本連載ではこれら2点についての詳しい説明を省略したいと思います。
プロパティとは、JavaBeansの属性を表すものです。一言でいえば、「Javaクラスのフィールド(インスタンス変数)をカプセル化したもの」です。
ここで例えば、商品在庫を表すJavaBeans「Zaiko」を以下のように定義したとしましょう。
public class Zaiko { public int count = 0; }
ここで、フィールドcountは、商品の在庫数を保持するものとします。例えば、在庫数をセットするには以下のようなコードを書きます。
zaiko.count = 1;
しかし、このようにpublicフィールドに対してほかのクラスから直接アクセスするような設計には、いくつか問題があります。
例えば、「countフィールドにはマイナスの値をセットしてはならない」という要件があったとします。すると、同フィールドにアクセスするすべてのコードで、以下のようなロジックを付加する必要が生じます。
if (c >= 0) { zaiko.count = c; }
もしこの要件が変更されたら、これらのコードをすべて書き直さなくてはなりません。つまり、柔軟性や保守性の低いアプリケーションとなってしまうのです。また、チーム開発を行っている場合は、ほかの開発者がcountフィールドを“予想外”の使い方をしてしまう可能性もあります。
例えば、上述のようなロジックを付け忘れ、countフィールドにマイナスの値を入れてしまうかもしれず、バグの温床となります。
そこで、上記のZaikoクラスを以下のように書き換えてみます。
public class Zaiko { private int count = 0; public void setCount(int c) { if (c < 0) { // 例外を送出 } count = c; } }
まず、countフィールドのアクセス修飾子をpublicからprivateに変更し、ほかのクラスから読み書きできないようにします。続いて、同フィールドに値をセットするためのsetCountメソッドを定義します。同メソッドでは、引数で渡された値をチェックし、ゼロ以上である場合にのみcountフィールドにセットするコードを記述します。
このように、クラスのフィールドを外部から隠し、必ずメソッドを通してアクセスさせるやり方を「カプセル化(encapsulation)」と呼び、カプセル化されたフィールドのことを「プロパティ」と呼びます。
フィールドの代わりにプロパティを用いることで、まず「柔軟性・保守性が向上する」というメリットが生まれます。
Zaikoクラスの例では、在庫数チェックのビジネス・ロジックが同クラスの外側に分散せず、setCountメソッドに集約されます。ビジネス・ロジックの変更やデバッグはsetCountメソッド1カ所の修正だけで済むため、仕様変更の要求にも積極的に応えられます。また、ほかの開発者によってフィールドが予想外の値にセットされる可能性がなくなり、バグの発生を少なくできます。
また在庫数チェック以外にも、例えば「プロパティの値が変更されたらログに記録したい」「プロパティの値が変更されたら別のプロパティの値も自動的に変更したい」といった多彩なロジックをプロパティに持たせることができます。
つまりプロパティとは、「賢くなったフィールド」といえます。こうした賢いフィールド=プロパティを中心にJavaクラスを記述することで、オブジェクト指向言語としてのJavaのメリットを引き出すことができます。
アクセッサ・メソッドの書き方
では、JavaBeansのプロパティはどのようにして実装すればよいのでしょうか。そのためには、以下のルールに沿ってコードを書く必要があります。
- プロパティの値を収めるフィールドはprivateにする
- プロパティの値を読み書きする「アクセッサ・メソッド」を用意する
まず上述したように、プロパティの値を収めるためのフィールドはprivateで宣言します。続く「アクセッサ・メソッド」とは、プロパティにアクセス(読み書き)するためのメソッドのことです。アクセッサ・メソッドには、「getterメソッド」と「setterメソッド」の2種類があります。
getterメソッド
getterメソッドは、プロパティの値を読み込むためのメソッドであり、以下のルールに従って定義します。
public <プロパティの型> get<プロパティ名>()
例えば、上記のcountプロパティのgetterメソッドは、以下のように定義します。
public int getCount() { // 略 }
この例のように、getterメソッドはプロパティの型(上記例ではint)の戻り値を返します。メソッド名は「get+プロパティ名」(1文字目は大文字)とし、引数は取りません。
なお、プロパティの型がbooleanの場合は、「is+プロパティ名」というメソッド名とすることも可能です(例えば、isEmptyなど)。
setterメソッド
setterメソッドは、プロパティの値をセットするためのメソッドであり、以下のルールに従って定義します。
public void set<プロパティ名>(<プロパティの型> <引数名>)
例えば、上記のcountプロパティのsetterメソッドは、以下のように定義します。
public void setCount(int i){ // 略 }
この例のように、setterメソッドは戻り値を返しません。メソッド名は「set+プロパティ名」(1文字目は大文字)とし、プロパティの型(上記例では、int)の引数を1つだけ取ります。なお、リードオンリー(読み込みのみ)のプロパティにはsetterメソッドを定義する必要はありません。
TomcatなどのWebコンテナ、またGUI開発ツールなどにJavaBeansコンポーネントを読み込ませると、まずJavaBeansを構成するJavaクラスのメソッドを1つずつ調べられます。このとき、「setXXX」「getXXX」といったメソッドが用意されていれば、「XXX」というプロパティが存在する、と判断される仕組みです。
ちなみに、アクセッサ・メソッドさえ定義されていれば、プロパティの値を収めるフィールドは必ずしも必要ではありません。
例えば、プロパティの値を動的に算出できる場合は、フィールドを宣言せずにアクセッサ・メソッドだけでプロパティを構成できます。
以上、今回はJavaBeansのプロパティの意義と使い方について説明しました。
Copyright © ITmedia, Inc. All Rights Reserved.