キモいVisitorパターン
Jiemamyのコーディングをゴリゴリやっている。
Jiemamyは多くの複雑なモデルクラスを持っているのだが、その各モデルに便利メソッドを色々追加していると、カオスになってくる。そこで、Visitorパターンを使って便利メソッドを全てクラス化してみている。
/** * オブジェクトに対して実行する処理のインターフェイス。 * @author daisuke * @param <R> 結果の型 * @param <T> 処理対象のオブジェクトの型 */ public interface Processor<T, R> { /** * オブジェクトに対する処理を実行する。 * @param target 対象オブジェクト * @return 結果 */ R process(T target); } public class Model { private String str1; private String str2; // accessor省略 /** * {@link Processor}による処理を実行する。 * @param <R> 処理結果の型 * @param <T> 処理対象モデルの型 * @param processor 実行するプロセッサ * @return プロセス結果 */ @SuppressWarnings("unchecked") public <R, T extends Model>R process(Processor<T, R> processor) { return processor.process((T) this); } }
このModelに以下のようなメソッドを追加していくと、キリがなく、見通しが悪くなってくる。
public String concat() { return str1 + str2; }
そこで上記のようなprocessメソッドを用意しつつ、concatメソッドの代りに以下のようなProcessorを書く。
public class ConcatProcessor implements <Model, String> { public String process(Model model) { return model.getStr1() + model.getStr2(); } }
そすると、以下のように使える。
Model model = new Model(); model.setStr1("Miyamoto"); model.setStr2("Daisuke"); String result = model.process(new ConcatProcessor()); // "MiyamotoDaisuke"
こうする事により、モデルクラスはaccessorとprocessメソッドのみで作る事ができ、整理される。まぁこの時点で、Visitorに慣れていなければそれなりにキモいかもしれない。
しかし途中で問題にぶち当たった。チェック例外を投げたいメソッド(Processor)と、そうでないメソッド(Processor)があるのだ。
そこでこんなのを試してみた。
/** * (略) * @param <E> 処理が投げる可能性のある例外の型 */ public interface Processor<T, R, E extends Exception> { R process(T target) throws E; } public class Model { private String str1; private String str2; // accessor省略 @SuppressWarnings("unchecked") public <R, T extends Model, E extends Exception>R process(Processor<T, R, E> processor) thrwos E { return processor.process((T) this); } }
で、例外を投げないProcessorと投げるProcessorは以下のように…。
/** 投げない */ public class ConcatProcessor implements <Model, String, RuntimeException> { public String process(Model model) { return model.getStr1() + model.getStr2(); } } /** 投げる */ public class HogeConcatProcessor implements <Model, String, HogeException> { public String process(Model model) throws HogeException { if(model.getStr1() == null || model.getStr2() == null) { throw new HogeException(); } return "Hoge"+ model.getStr1() + model.getStr2(); } }
クライアント側。
Model model = new Model(); model.setStr1("Miyamoto"); model.setStr2("Daisuke"); String result = model.process(new ConcatProcessor()); try { String resultHoge = model.process(new HogeConcatProcessor()); } catch (HogeException e) { // ... }
どーーーだ!! ...一般的じゃないから可読性は悪いよなぁ><;