Step3:リフレクションAPIで変換ルールを動的に適用する
Step3ではいよいよ読み取ったデータの変換処理を組み込みます。変換ルールはデータ項目に応じて異なるので、
下ごしらえとして、
次に、
最後に、
①で設定ファイルの
そして、
Converter converter = new IntegerConverter();
リフレクションAPIを使用することで、
public interface Converter {
Object convert(Object value);
}
public class IntegerConverter implements Converter {
public Object convert(Object value) {
return Integer.parseInt(value.toString());
}
}
public class DateConverter implements Converter {
public Object convert(Object value) {
try {
return new SimpleDateFormat("yyyyMMdd")
.parse(value.toString());
} catch (ParseException e) {
throw new RuntimeException(e);
}
}
}
public class TrimConverter implements Converter {
public Object convert(Object value) {
return StringUtils.trim(value.toString());
}
}
private static class MessageParser {
...
public void parse() throws Exception {
while (index < bytes.getLength() - 1) {
Map<String, Object> record =
new HashMap<String, Object>();
for (int i = 0; i < config.getRowSize(); i++) {
DataRow row = config.getRow(i);
String name =
(String) row.getValue("データ名称");
int length =
((BigDecimal) row.getValue("バイト数"))
.intValue();
String ruleClassName = ┓
(String) row.getValue("変換ルール"); ┛①
String value = getString(length);
Class<?> clazz = Class.forName(ruleClassName); ┓
Converter converter =   |
(Converter)clazz.newInstance(); ┛②
Object newValue = converter.convert(value); ―③
record.put(name, newValue);
}
System.out.println(record);
}
}
...
}
No | データ名称 | 長さ | 変換ルール |
---|---|---|---|
1 | 送信日 | 8 | gcw. |
2 | ユーザ名 | 10 | gcw. |
3 | メールアドレス | 20 | gcw. |
4 | ポイント | 5 | gcw. |
考察1:ストラテジパターン
この例のように、
考察2:複数の変換パターンを適用したい場合には?
Step3のコードには問題があります。
まず、
そのほかの問題として
方法1:DSLのルールで対応する
たとえば
方法2:式言語やスクリプト言語を利用する
OGNL
どちらの方式であっても、
No | データ名称 | 長さ | 変換ルール |
---|---|---|---|
1 | 送信日 | 8 | new DateConverter2("yyyyMMdd") |
2 | ユーザ名 | 10 | new TrimConverter() |
3 | メールアドレス | 20 | new TrimConverter() |
4 | ポイント | 5 | [new TrimConverter(), new IntegerConverter()] |
考察3:DSLの構文を改善するには?
改善1:変換ルールに短い別名を付ける
表3の
表5のようにそれぞれのクラス名に
date=gcw.gcw5.converter.DateConverter
trim=gcw.gcw5.converter.TrimConverter
integer=gcw.gcw5.converter.IntegerConverter
あとはフレームワーク側でマッピングのプロパティファイルを読み込んで、
No | データ名称 | 長さ | 変換ルール |
---|---|---|---|
1 | 送信日 | 8 | date |
2 | ユーザ名 | 10 | trim |
3 | メールアドレス | 20 | trim |
4 | ポイント | 5 | integer |
改善2:デフォルトで両端空白除去する
両端空白除去
DSLを取り入れた開発では、
「短い別名」
考察4:テストについて
このような
テストコードは配布用サンプルに含んでいます。テストコードは
考察5:デバッグについて
DSLでは、
考察6:フレームワーク? それともDSL?
今回のサンプルはフレームワークでしょうか? これはフレームワークです。ではDSLでしょうか? これは意見が分かれるかもしれませんが、
今回のまとめ
今回はメタプログラミングの適用例としてExcelによるDSLを取り上げました。普段のプログラミングとは直接関係がなさそうな
お勧めサイト/書籍
- Martin Fowler's Bliki
「構文ノイズ」 - DSLにおける構文上のノイズに関する考察が書かれています。RubyやJava、
XMLなどでのDSLの構文例を挙げてその違いを比較しています。構文の違いで可読性や使い勝手がかなり異なることがよくわかります。 - 『増補改訂版 Java言語で学ぶデザインパターン入門』
結城 浩(著)、 ソフトバンククリエイティブ、 2004年 - 良い仕事をしたい普通のプログラマのためのデザインパターン入門本です。筆者はこの本のコードを2回写経して、
さらに応用したアプリケーションをいくつか書いてみることで、 抽象的に処理を扱う方法やフレームワークの作り方を学びました。たいへんわかりやすい本ですので、 まだ手に取られていない人はぜひ読んで、 ぜひ書いてみてください