Advice Reusability and Named Advice
名前つきアドバイスはなぜ必要か? たとえば:
とかが再利用可能な形で配布されてたとする。
public class Point {
private int x;
private int y;public Point(int x, int y) {
this.x = x;
this.y = y;
}public void setX(int x) {
this.x = x;
}
public void setY(int y) {
this.y = y;
}
}public aspect PointLogging {
pointcut methods() :
call( void Point.setX(int) ) || call( void Point.setY(int) );before() : methods() {
// log
}
}
AspectJ では、inter-type 宣言で外部からクラスの構造を変更できるので以下のように Point クラスを拡張できる:
しかし、どうやって、PointLogging アスペクトを setColor メソッドの振る舞いをログするように変更するのか? 現在の AspectJ では、どうしようもない気がする。つまり、before() : methods() { ... } の部分は再利用可能でない。
public aspect PointExtension {
private String Point.color;public void Point.setColor(String color) {
this.color = color;
}
}
問題は、以下の二点から考えられると思う:
- PointLogging アスペクトが変更(setColor メソッドなどが追加されたときにログが期待通りに動作しない)を予期しないような悪い設計になっていた。
- AspectJ が適切なメカニズムを提供していないのが悪い。
前者の視点からは、たとえば(コンパイルしてないので何が不具合があるかもしれないけど)、
みたいに設計されていれば:
public abstract aspect AbstractPointLogging {pointcut abstract methods();
before() : methods() {
// log
}
}
public aspect PointLogging extends AbstractPointLogging {
pointcut methods() :
call( void Point.setX(int) ) || call( void Point.setY(int) );
}
というふうにできたかもしれない(コンパイルしてないので誤っている可能性あり)。
public aspect PointExtensionLogging extends AbstractPointLogging {pointcut methods() : call( void Point.setColor(String) );
}
後者の視点からは、もし、アドバイスに名前があるのであれば:
というふうにできるかもしれない。
public aspect PointLogging {pointcut methods() :
call( void Point.setX(int) ) || call( void Point.setY(int) );before set() : methods() {
// log
}
}public aspect PointExtension {
private String Point.color;public void Point.setColor(String color) {
this.color = color;
}PointLogging.set() : // アドバイスの指定
pc() || // オリジナルのポイントカット
call( void Point.setColor(String) ); // 追加するポイントカット
}
あるいは、アドバイスをポイントカットが関連付けられた特殊なメソッドだと考えると:
ともできるかもしれない。
public aspect PointLogging { // 変更なしpointcut methods() :
call( void Point.setX(int) ) || call( void Point.setY(int) );before set() : methods() {
// log
}
}public aspect PointExtension {
private String Point.color;public void Point.setColor(String color) {
this.color = color;
}before setColorCall() : call( void Point.setColor(String) ) {
PointLogging.aspectOf().set(); // アドバイスの直接呼出し
}
}
とすると、単にアドバイス内から直接メソッドを呼べば名前つきアドバイスなんていらないのでは、と思うかもしれない:
public aspect PointLogging { // 変更なしpointcut methods() :
call( void Point.setX(int) ) || call( void Point.setY(int) );before() : methods() { // 普通のアドバイス
log();
}public void log() {
// log
}
}public aspect PointExtension {
private String Point.color;public void Point.setColor(String color) {
this.color = color;
}before() : call( void Point.setColor(String) ) {
PointLogging.aspectOf().log(); // メソッドの直接呼出し
}
}
ということで微妙な結論に。