SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

DeveloperZine(デベロッパージン)- エンジニアの意思決定を支える技術情報メディア ProductZine

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

japan.internet.com翻訳記事

Jakarta Commonsを使ってJDKクラスを拡張する:パート1

Commons Validator/Collections/Chain/Functors/Langの利用

Chain

 Gang of FourのCOR(Chain of Responsibility)デザインパターンは、一群の操作をモデル化するのによく使われます。各操作をコマンドオブジェクトとしてモデル化し、他のオブジェクトとリンクしてチェーンにする必要があります。これらのコマンドオブジェクトはデータに作用し、チェーンの次のコマンドに制御を渡すべきかどうかを示します。コードに変更を加えなくても操作を簡単に追加/削除できるのが利点です。実行が成功するためには、コマンドの実行時にコマンドラインから渡された引数とサブコマンドを処理コードで利用できなければなりません。

 Commons Chainコンポーネントは、アプリケーション内でこのパターンを使用するのに必要なインターフェイスと実装を提供します。APIは明快で、理解するのも難しくはないでしょう。以降では、このコンポーネントを現実の問題に適用することで用法を説明していきます。CLI(Command Line Interface)アプリケーションを開発したり使用したりした経験のある開発者は少なくないと思います。本稿のCommons Chainのサンプルは、HTTP、FTP、PINGという基本的なネットワークプロトコルを使用するためのCLIアプリケーションです(ソースコードについては「in.co.narayanan.commons.chain」パッケージを見てください)。次のリストはいくつかのコマンドを抜粋したものです。

java CommandProcessor ''-user'' admin ''-password'' manager ''-ping'' {host}
java CommandProcessor ''-user'' admin ''-password'' manager
 ''-ftp'' {host} ''-get'' {path_to_file}
java CommandProcessor ''-user'' admin ''-password'' manager
 ''-http -get'' {path_to_file}

 今回のサンプルでは、-user引数と-password引数を使って、ネットワークコマンドではなくローカルデータベースに対してユーザーの妥当性検査を行います。-get引数は、-ftp-httpという両マスタコマンドについて、指定のURLのファイルを取得するためのサブコマンドです。ここではCommons Chainの使用例を示すことが狙いなので、この実装にはスケルトンコードしか入っていません。そのため、-pingコマンドの実行時にはコンソールにログメッセージが表示されるだけで、実際にターゲットに接続することはありません。あとは各自で完全なアプリケーションに仕上げてください。その際はCommons Net APIを使用するようお勧めします。

 この問題に対してCORパターンを使用すると、デザインが大幅に簡素化されてモジュール性が向上します。

CLIコンテキスト

 CLIコマンドの実行時に操作が正常に行われるためには、処理コードで引数とサブコマンドを利用できる必要があります。CommandlineContextクラスとCLICommandクラスはドメインオブジェクトで、これらはコマンドとサブコマンドと引数を表現します。

 CLICommandは自分自身への参照を持っています。これはサブコマンドを表現するためのCompositeデザインパターン実装であり、これにより任意の数のコマンドをネストすることが可能になります。CLICommandのインスタンスはuserpasswordと一緒にCommandlineContextに入れられるので、実行されるCLI操作の全情報を表現します。コンテキストは実行時にチェーン内のコマンドに渡されます。コンテキスト情報を利用したり制御を次のコマンドに渡したりするのは、チェーン内の各コマンドが行います。

 このサンプルではCLIの引数をプライベート変数として表現し、ゲッターメソッドを使ってアクセスします。代替策としてContextBase実装を使用する方法もあります。この方法ではJava Beanイントロスペクションを使って属性値を取得し、Mapビューを提供します。したがって、getUsergetPasswordのような専用ゲッターメソッドをget("user")get("password")で置き換えることができます。

チェーン内のコマンド

 コマンドに必要なコンテキスト情報を表現したら、次にコマンドとチェーンとサブチェーンをモデル化します(後ほどCommons Chain APIでコマンドとチェーンをどのように実行するかを示します)。Pingクラスは-pingのために実行されるコマンドです。このクラスはexecuteメソッドに渡されたコンテキストを使って、コマンドタイプが-pingかどうかをチェックします。コマンドタイプが他のものなら、このメソッドはfalseを返して、チェーン内の次のコマンドに制御を渡す必要があることをChainフレームワークに知らせます。

 Ftpクラスはマスタコマンド-ftpを表現します。したがって、ftpのサブコマンドである-get-lsを処理するために、これはChainBaseのサブクラスとしてモデル化されます。実行メソッドはコマンドタイプをチェックします。それが-ftpなら、このチェーン内のFtpGetコマンドとFtpLsコマンドを実行するために基本クラスのexecuteが呼び出されます。このアプリケーションでは、コマンドに-http -getなどのサブコマンドが含まれていれば、それはChainとしてモデル化され、該当するコマンド制御が委ねられます。

チェーン

 このアプリケーションで使われるチェーンとコマンドを視覚的に表現すると、次のようになります。

Main Chain
Authenticator (Verifies user and password) --> Ping (Command) --> 
   Ftp (Sub-chain A) --> Default (Prints invalid command message)

Sub-chain A
FtpGet (Command) --> FtpLs (Command)

 チェーンはChainBaseクラスまたはCatalogBaseクラスを使って実行時にプログラム内から作成できます。代替策として、XMLファイル内でコマンドとチェーンを指定し、ConfigParserを使ってチェーンを構築するという方法もあります。今回のサンプルで使用する「catalog.xml」ファイルは以下のとおりです。

<?xml version="1.0" ?>
<catalog>
   <chain name="CommandProcessor">
       <command name="authenticate"
          className="in.co.narayanan.commons.chain.Authenticator"/>
       <command name="ping"
          className="in.co.narayanan.commons.chain.Ping"/>
       <chain name="ftp"
          className="in.co.narayanan.commons.chain.Ftp">
           <command name="get"
              className="in.co.narayanan.commons.chain.FtpGet"/>
           <command name="ls"
              className="in.co.narayanan.commons.chain.FtpLs"/>
       </chain>
       <command name="default"
          className="in.co.narayanan.commons.chain.DefaultCLICommand"/>
   </chain>
</catalog>

フレームワークのセットアップと実行

 次のリストはCommons Chainフレームワークをセットアップして実行するためのコードです。

ConfigParser parser = new ConfigParser();
parser.parse(getClass().getResource("catalog.xml"));

Catalog catalog = CatalogFactoryBase.getInstance().getCatalog();
....

Command command = catalog.getCommand("CommandProcessor");
command.execute(getPingCommand());
command.execute(getFtpGetCommand());
command.execute(getFtpLsCommand());
command.execute(getInvalidCommand());
command.execute(getInvalidCredentials());

 「catalog.xml」ファイルが解析され、結果としてCatalogの参照がCatalogFactoryBaseから取得されます。これで各CLIコマンドの呼び出しの「モックアップ」ができたことになります。完全なコードはテストケースクラスTestChainに収められています。なお、別個のクラスでコマンドライン入力を解析してコンテキストオブジェクトを作成し、それらをチェーンに渡すのが理想的です。その際はCommons CLIを使用することができます。

次のページ
Functors

この記事は参考になりましたか?

japan.internet.com翻訳記事連載記事一覧

もっと読む

この記事の著者

japan.internet.com(ジャパンインターネットコム)

japan.internet.com は、1999年9月にオープンした、日本初のネットビジネス専門ニュースサイト。月間2億以上のページビューを誇る米国 Jupitermedia Corporation (Nasdaq: JUPM) のニュースサイト internet.comEarthWeb.com からの最新記事を日本語に翻訳して掲載するとともに、日本独自のネットビジネス関連記事やレポートを配信。

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

Narayanan A.R.(Narayanan A.R.)

テスト駆動開発、アジャイル方法論、Javaテクノロジ、およびデザインパターンの熱烈な擁護者。Javaテクノロジを使ったソフトウェアのデザインおよび開発に携わって数年になる。

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

CodeZine(コードジン)
https://codezine.jp/article/detail/283 2006/04/11 19:09

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー