public class Client { public static void main(final String[] args) throws Exception { new UsingA() { A r1 = new A("r1"); { new UsingB() { B r2 = new B("r2"); { new UsingA() { A r3 = new A("r3"); { r1.use("x"); r2.use("y"); r3.use("z"); }}; }}; }}; } }、、、自動的に r3, r2, r1 の順にリソースが解放されるようにしてみたい。(前回までのコードでは r1 が解放されず r3 が2度解放されてしまっていた。) 以下のように Stack を使って UsingAspect を修正。ついでにマルチスレッドで使えるように
percflow(using())
をアスペクト定義に付与。
public abstract aspect UsingAspect<T, U> percflow(using()) { protected Stack<T> stack = new Stack<T>(); pointcut settingField(T o): set (T+ U+.*) && args(o); pointcut using(): call(U+.new(..)); after(T o): settingField(o) { this.stack.push(o); } after(): using() { if (!stack.empty()) endUsing(this.stack.pop()); } protected abstract void endUsing(T o); }その他のクラスは、ほとんど自明だけど以下のようなものになる。
UsingA
public interface UsingA { public static aspect AspectA extends UsingAspect<A, UsingA> { @Override public void endUsing(A o) { if (null != o) o.dispose(); } } }
UsingB
public interface UsingB { public static aspect AspectB extends UsingAspect<B, UsingB> { @Override public void endUsing(B o) { if (null != o) o.close(); } } }
A
public class A { private final String name; public A(String name) { this.name = name; } public void dispose() { System.out.printf("%s disposed%n", this); } public void use(String str) { System.out.printf("%s used with \"%s\"%n", this, str); } public String toString() { return String.format("A(\"%s\")", this.name); } }
B
public class B { private final String name; public B(String name) { this.name = name; } public void close() { System.out.printf("%s closed%n", this); } public void use(String str) { System.out.printf("%s used with \"%s\"%n", this, str); } public String toString() { return String.format("B(\"%s\")", this.name); } }実行すると以下のようなコンソール出力を得る。
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 件のコメント:
コメントを投稿