今日、メンバーと話をしていて面白かったのでコーディングしてみました。
メタプログラミングっぽくDIコンテナを利用する
XMLの名前空間をトリガーにしてローカル名でオブジェクトを発見し、処理を委譲するというアイデアです。例えば名前空間がcommandとして、そのローカル名でDIコンテナをルックアップします。
<コマンド定義ファイル test.xml>
<?xml version="1.0" encoding="UTF-8"?>
<commands xmlns:command="http://www.arclamp.jp/command">
<command:out command:message="ほげほげ" />
</commands>
DIコンテナの設定ファイルはこんな感じ。command:outという指定なので、commandsプロパティにoutというキーでBeanをインジェクトします。
<Springのサンプル設定ファイル test-applicationContext.xml>
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.0.xsd">
<bean id="parser" class="jp.arclamp.metadi.impl.ParserImpl">
<property name="commands" >
<map>
<entry key="out">
<bean class="jp.arclamp.metadi.commands.OutCommand"/>
</entry>
</map>
</property>
</bean>
</beans>
コマンドを追加したいなら設定ファイルに新しいエントリを追加するだけで済みます(本当は名前空間に対応したxsdも必要でしょうが)。今回はXMLの名前空間をトリガーにして対象に処理をしていますが、もっとシンプルに要素名で処理をしてもいいでしょう。ここらへんはアイデアしだいということで。
こういうことをしていると設定ファイルがDSLという位置づけになり、JavaコードはDSLのコンテナという理解をすることができます。
Genericsを利用したインターフェース定義
もう1つはGenericsの活用。コマンドのクラス(この場合は(OutCommand)は、インターフェースCommandを実装しなくてはいけません。
<コマンドのインターフェース:Command.java>
package jp.arclamp.metadi;
public interface Command<T> {
public void execute(T params);
}
コマンドの実行メソッドexecuteのパラメタがGenericsで指定されています。なので、実装する場合は、次のような感じになります。パラメタオブジェクトを自分で指定できるのでコードが曖昧になりません。
<コマンドの実装クラス:OutCommand.java>
package jp.arclamp.metadi.commands;
import jp.arclamp.metadi.Command;
public class OutCommand implements Command<OutParameter> {
public void execute(OutParameter parameter) {
System.out.println(parameter.getMessage());
}
}
<パラメタオブジェクトのクラス:OutParameter.java>
package jp.arclamp.metadi.commands;
public class OutParameter {
private String message;
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}
コマンドオブジェクトを呼び出すときにはリフレクションAPIを使ってGenericsのクラスを取得しパラメタオブジェクトをインスタンス化します。あとはパラメタオブジェクトに対してXMLの属性に従ったセッターインジェクションで値を設定しています(リフレクションAPIによるDI処理)。
こんな風にDIコンテナやGenericsを使うことでアプリケーションの部分を取り出してフレームワーク化すると、pojoを保ちつつ静的型付けを活かすことができます。品質や効率化についても貢献することでしょう。
サンプルコード(Maven2対応)はこちら。自由に使ってください。適当コーディングなのでご注意を。あと、もっと良いアイデアがあったら教えてくださいね。
