Wicketで始めるオブジェクト指向ウェブ開発

第2回 コンポーネントとモデル

この記事を読むのに必要な時間:およそ 4.5 分

コンポーネントはオブジェクト

Labelコンポーネントを作るたびに第2引数に渡す引数を変更すれば,HomePageを表示するたびにメッセージを変更することもできそうです。その方法はHomePageクラスでは使用可能ですが,Wicketのあらゆるページで使用可能な方法ではありません。ここからWicketのオブジェクト指向の世界に入っていきます。

オブジェクト指向言語における「オブジェクト」にはさまざまな性質がありますが,重要な機能として「自分自身の状態を自分で保持できる」という点があります。オブジェクトは,自分がどういう状態なのかを知っています。オブジェクト指向プログラミングの世界でテレビというオブジェクトのスイッチを入れれば,テレビは現在スイッチがオンであるということを自分自身の中に保持するでしょう。その情報はセッションに格納されたりはしません。

たとえば「そのHTML要素は表示されるかどうか」という状態も,コンポーネントが管理する情報のひとつです。Labelコンポーネントは自分が表示されるべきかどうかを知っています。Wicketは,タグを表示するときに,表示してよいのかどうかを各コンポーネントに問い合わせます。

コンポーネントが表示されるかどうかは,isVisible()メソッドを介して制御されます。

次のようにLabelのisVisible()メソッドを「常にfalseを返す」と再定義すれば,Labelを適用した<span>タグは二度と表示されません※2)⁠

リスト3 Labelを非表示にする

add(new Label("message", "If you see this message wicket is properly configured and running") {
  public boolean isVisible() { return false; }
});

Labelが表示されるべきかどうかはLabel自身によってコントロールされるべきで,外部から操作することで切り替えるものではない,というのが,Wicketの基本的な考え方です。

このプログラムでは毎回falseが返却されますが,たとえば,現在時刻の「分」が偶数の時だけtrueを返す,というプログラムをここに書くことで,Labelは偶数分の時だけ表示されるようになります。Label自身が自分を表示すべきかどうかを管理するのです。

※2
このLabelクラスの特殊な書き方は「匿名サブクラス」と呼ばれる手法です。クラス定義を別途書くことなく,その場でサブクラス化してメソッドの再定義を行います。Webアプリケーション開発ではほとんど使われませんが,デスクトップ・アプリケーションなどの領域では積極的に使われる技法です。Wicketでも,この技法を多用します。

オブジェクト自身に表示を変えさせる

Wicketでは,ページやコンポーネント自身が情報を保持できます。HomePageページは単純な表示のみのページなので,毎回ページを作り直してもよいでしょう。しかし,ページへの入力が行えるようなページでは,ページの状態はユーザの入力によって次々と変化していきます。そのとき,ページやコンポーネントは毎回作られるのではなく,一度作成したページやコンポーネントが続けて使用されます。当然です。ページやコンポーネントが情報を保存しているのですから,毎回消えて再作成されても困るのです。以前の状態を持っている,同じオブジェクトが使われなければいけません。

ということは,ページやLabelのコンストラクタは一度しか呼び出されない可能性があるということです。コンストラクタで毎回Labelの第2引数を変更する,という方法では駄目なことがあるのです。

Labelが表示する内容が毎回変化するのであれば,次に表示すべきメッセージは何なのか,Label自身が知っているべきです。そうすることにより,このLabelはページとは切り離しても「毎回表示するメッセージが変わるLabel」という独立した存在になり得ます。これがオブジェクト指向の便利なところです。

そこで,Labelオブジェクトを作るときにコンストラクタで表示メッセージを指定するのではなく,Label自身が,表示されるときにメッセージを決定できる方法が良さそうです。

モデルによるコンポーネントとデータの分離

しかしそうはいっても,表示するメッセージ毎に新しいLabelサブクラスを作っていてはきりがありません。へたしたらページを作るたびに新しいLabelクラスを作る羽目になりそうです。

Wicketでは,そのために「表示を制御するコンポーネント」「データを制御するオブジェクト」とを分離しました。Labelが表示すべきデータを決定する,という機能を別のオブジェクトとすることで,データの決定方法をプラグイン可能にしたのです。

表示すべきデータなしには,表示の制御を行うことはできません。コンポーネントは,モデルと組み合わせることではじめて機能するのです。両者を別にしたことで「⁠どのようなメッセージかは決まっていないが)メッセージをランダムに表示するLabel」というコンポーネントを作ることができます。このLabelは,データを提供する「モデル」を差し替えることで,どこででも使うことができます。

Labelは,モデルを与えられると,モデルを自分自身の中に保持します。データ自体ではなく,データを提供してくれるオブジェクトを保持するのです。以降,Labelは表示を行うたびに,表示すべきデータをモデルから提供してもらいます。

Labelコンポーネントの機能をより正確に表現すると,⁠モデルによって提供されたデータをHTML要素内に表示する」という機能を持ったコンポーネント,ということになります。

著者プロフィール

矢野勉(やのつとむ)

フリーランスのプログラマ。Wicket-ja主催。

ウェブ・アプリケーションの開発を中心にさまざまな案件に関わってきました。現在はWicketによる開発を支援しています。

URLhttp://d.hatena.ne.jp/t_yano/

著書