オブジェクト指向プログラミングでは、ビジュアル環境(IDE:Integrated Development Environmentsなど)で部品を配置する感覚でプログラミングが行えます(全てではないが...)。JavaBeansは、以下のようなプログラミングを実現できるような部品となる Javaオブジェクトクラスを指します。
Java Beansプログラミングというと、「beans を利用してプログラムを作成する」「beans 自身を作成する」の二通りに分類できます。beans を利用してプログラムを作成する場合、アプリケーションを作成する一般的なプログラミングです。しかし、 beans 自身を作成する場合、アプリケーションのプログラミングに必要な機能の実現だけでなく、再利用可能となるような設計、動作をテストする機能、セキュリティの問題を意識しなくてはなりません。さらに、beans はデバッグされているものとして利用され、利用する側ではデバッグを行わないため、高性能/高品質でなくてはなりません。
Beansは、比較的小さなコンポーネントを目指したもので、単純なプログラミングで基本動作でカバーできるものを想定しています。 Beansの APIは、各プラットフォームで何らかの形でサポートされていなければなりません。つまり、Beansの APIに従って Beanコンポーネントを開発すれば、いろいろなプラットフォームで何らかの形(表示方法とは違えど)で動作することを保障します。
全ての Beanの動作を決める親クラスを定義するのではなく、各コンポーネント自身が標準的な動作をサポートすることを推奨します。しかし、標準的な動作をしないからといってこれを排除するものではありません。
Beans を実現するための基本的なフレームワークは以下のようなものです。
Bean を作成するにあたって意識しなくてはならないこと
Beans.getInstanceOf()を使って
Beanオブジェクトを取り出す必要があるBeans は、あるコンポーネントが発生するイベントや、あるコンポーネントが受け取るイベントが何かを知っている必要があります。JDK では、動的にイベントの送受信が可能なように「イベントリスナー」オブジェクトというフレームワークが導入されています。これは、イベントを受信して処理するオブジェクトに対し、イベントオブジェクトを引数とするメソッド(イベントハンドラ)を用意してイベントソースオブジェクトからこのメソッドを呼び出してもらうことにより、イベントの交換をしようというものです。 イベントソースオブジェクトは、 イベントリスナーを登録するメソッド(add <イベント名> Listener()) と削除するメソッド(remove <イベント名> Listener())を用意し、 ある処理が実行されると適当なイベントオブジェクトを作成した上で登録されたイベントリスナーのメソッドを呼び出します。
《イベントリスナー》
Vector.close()などを使ってマルチスレッドを意識する必要があります。 《イベントアダプタ》
イベントのクラス名、リスナーのクラス名、および add, removeメソッドの名前が対応していることに注意しなければなりません。 これは、Beans を読み込む開発ツールが、これらの名前を参照することでどのイベントソースと、どのイベントリスナーがイベント交換可能かどうかを判断するのに必要になります。
public class XXX extends EventObject;
interface XXXListener extends EventListener {
void xxxXxxxXxxx(XXX ev);
void xxxXxxxXxxx(XXX ev);
void xxxXxxxXxxx(XXX ev);
}
class Xxxx implements XXXListener;
public void addXXXListener(XXXListener l);
public void removeXXXListener(XXXListener l);
サンプルコード:
【イベントオブジェクト】
class MyEvent extends AWTEvent {
Object source;
public MyEvent(Object obj, int code) {
super(obj, iCode);
// 必要であればイベントソースオブジェクトを記憶しておく
source = obj;
}
}
【リスナーのインターフェース】
public interface MyEventListener {
public void handleMyEvent(MyEvent evt);
}
【イベントソース】
class MySource {
MyEventListener listener;
public void addMyEventListener(MyEventListener lis) {
listener = lis;
}
public void removeMyEventListener(MyEventListener lis) {
if( listener == lis ) {
listener = null;
}
}
public static void main(String args[]) {
.
.
// イベントオブジェクトを生成(または何らかの方法で)して
// イベントリスナーのイベントハンドラを呼ぶ
MyEvent event = new MyEvent(this, i);
listener.handleMyEvent(event);
.
.
}
}
【イベントリスナー】
class MyListener implements MyEventListener {
// MyEventListenerのインターフェースに従って handleMyEvent()メソッドを用意する
public void handleMyEvent(MyEvent event) {
// 送ったイベントのオブジェクトを得る: event.getSource()
// イベントの ID を得る: event.getID()
// などなど
}
}
プロパティの値は、常に専用のメソッド(アクセスメソッド)を通して Beansオブジェクトの利用者(開発ツールなど)からアクセスされます。
二種類のメソッドが用意されています。
プロパティ値の参照は、「getXXXX()」という名前のメソッドを呼び出すことで行われ、 「XXXX」の部分がそのプロパティ名となるように記述します。
プロパティ値の変更は、「setXXXX()」という名前のメソッドを呼び出すことで行われ、 「XXXX」の部分がそのプロパティ名となるように記述します。
getXXXX()やsetXXXX()を用意したBeanを、デザインシートに張り付けると 「XXXX」という名前のプロパティがプロパティシートに表示されます。
void setXXXX(int index, XXXX val); XXXX getXXXX(int index); void setXXXX(XXXX val[]); // 配列のサイズを変更したい場合、これですべてセットし直す XXXX[] getXXXX();
public void addPropertyChangeListener(PropertyChangeEvent ev);
public void removePropertyChangeListener(PropertyChangeEvent ev);
PropertyChangeEvent内には Localeに依存しないプロパティ名を指示し、自分の内部状態を更新してからこのイベントを投げる。
PropertyChangeSupportクラスを使うことで楽にこのイベントを処理でます。
もし、このプロパティが変更されたら、BeanはVetoableChangeListener.veto ableChnage()メソッドを呼び出します。このとき引数にPropertyChangeEventを渡します。この結果、変更して欲しくないものの場合は PropertyVetoExceptionが発生します。1つ以上のリスナーが拒否した場合は、元の値に戻し、かつ戻したことを知らせる PropertyChangeEventを発生させる必要があります。
vetoableChange()メソッドの呼び出しは値の変更前に実行しなければなりません。VetoableChangeSupportクラスを使うと便利です。また、同時に PropertyChangeイベントも発生させるべきです。あるプロパティの変更に対し、2回イベントを発生させる必要があります。VetoableChangeのみで処理すると、本当に値に反映したかどうかの確認ができません。
《メソッド》
setXXXX()で渡された値が同じものなら何もしない(イベントを発生しない)のが良い。 addXXXListener()もあり add
<propertyname>
Listener()や remove
<propertyname>
Listener()というメソッドも
OK メソッド名などからでは入手不可能な Bean のプロパティ等を調べるプロセスをイントロスペクション(Introspection) と呼びます。これは、あるBeansクラス(MyObjectとする)に対して、BeanInfoクラス(名前は「MyObjectBeanInfo」)を作成し、 そのBeanInfoクラスの中で不足している情報を提供するコードを記述するという方法です。
また、リフレクション(Reflection) と呼ばれる技術によって、任意のオブジェクトクラスが、どのような名前/引数/返り値のメソッドを持っているのかを リストアップすることがでます。 ビジュアル開発ツール(IDE) は、このリフレクションを使用してインストールされた各Beansクラスがどのようなメソッドを持つのかをチェックし、 イベントのメニューに表示したり、 プロパティシートにプロパティの名前を表示したりしています。
開発ツールは、イントロスペクションとリフレクションを利用することで、どのようなイベントを発生させたりどのようなイベントを受信したりするのか、 ターゲットのBeanクラスがどのようなプロパティを持っているのか等を読み取り、メニューへの表示やコードの自動生成などを行います。
getJavaInitializationString()を実装しなければなりません。
このメソッドは現在のプロパティの値に合わせて、再初期化時のコードを返します。(setXXXX()の引数部分のみ) MyObject obj = (MyObject)Beans.instantiate(null,"e;MyObject");このメソッドを呼び出すと、 次のどちらかの方法でオブジェクトをインスタンス化します。
このメソッドにより、インスタンス化しようとするオブジェクトが通常のオブジェクトクラスなのか、開発ツールによってプロパティ値をデザインされたオブジェクトクラスなのかをプログラム側で区別する必要がなくなります。
※)このinstantiate()メソッドの仕様上、 すべてのBeanクラスは引数の無いコンストラクタを用意する必要があります。
例えば、次のようなクラスファイルから構成されるBeanがあるとします。
開発ツールで、Beanを利用しようとする場合は、このクラスがまとめられた JARファイルを決められた手順に従ってインストールしなければなりません。
開発ツールは、インストールされている各JARファイルをスキャンして、 順番にBeanクラスを取り出します。このとき、1個のJARファイル中のどのクラスファイルが Beanクラスなのかを示すフラグを立てておく必要があります。そのフラグはManifestファイル(MANIFEST.MF) というテキストファイルに記述します。Manifestファイルは、JARファイルに含まれた全ファイルの情報(名前など)をテキストファイルとして格納したものです。
Manifestファイル(MANIFEST.MF)に追加する情報:
# cat MyBean.MF Manifest-Version: 1.0 Name: MyObject.class Java-Bean: True
JARファイルを作成:
# ls MyObject.class MyEvent.class MyEventListener.class MyBean.MF # jar cfm MyBean.jar MyBean.MF *.class
jarコマンドのオプションに "m" を追加し、Manifestファイル"MyBean.MF"を指定すると、 Beanとして JARファイルが作成されます。一つのJARファイル中の複数のクラスファイルに「Java-Bean: True」 のフラグを立てることで、複数のBeanクラスをパッケージ化することができます。