public abstract aspect UsingAspect<T, U> {
protected T obj;
pointcut settingField(T o): set (T+ U+.*) && args(o);
pointcut using(): call(U+.new(..));
after(T o): settingField(o) {
this.obj = o;
}
after(): using() {
endUsing(this.obj);
}
protected abstract void endUsing(T o);
}
この Generic な抽象アスペクトを、それぞれのリソース型について以下のように具体的する。
- 前回の Disposable オブジェクトの例。
public interface UsingDisposable { public static aspect DisposableAspect extends UsingAspect<Disposable, UsingDisposable> { @Override public void endUsing(Disposable o) { if (null != o)((Disposable)o).dispose(); } } } - java.io の Writer に適用する例
interface UsingWriter { public static aspect UsingWriterAspect extends UsingAspect<Writer, UsingWriter> { @Override protected void endUsing(Writer o) { try { if (null != o) o.close(); } catch (IOException ex) { throw new RuntimeException(ex); } } } }
pointcut using(): call(Using<T>+.new(..));
みたいなパラメタライズした書き方ができれば、更に堅牢で経済的なコードになるけど、残念ながら文法的に許されないらしい。)
クライアントコードは以下のようになる
public class Client {
public static void main(final String[] args) throws Exception {
new UsingWriter(){
PrintWriter s = new PrintWriter("test.txt"); {
s.println("one line written");
s.flush();
}};
}
}デバッガを使うとか、コンソール入力を待つ行を追加するとかして、適当な箇所で止めながら動かすと、無名クラス生成ブロックの中でだけ ファイル test.txt にロックがかかっているのが確かめられる。
あとはマルチスレッドとネストか。
}
}
実行すると以下のようなコンソール出力を得る。A("r1") used with "x"
B("r2") used with "y"
A("r3") used with "z"
A("r3") disposed
B("r2") closed
A("r1") disposed
割と簡単に using のネストができた。一応、だんだんと実用的になってきた気がする。取りあえずテストコードで使い始めて、パフォーマンスなんかを中心にしばらく観察してから、問題が無ければプロダクトコードで使ってみるような流れで良いか。
0 件のコメント:
コメントを投稿