Java におけるコード進化パターン (Code Evolution Patterns in Java) - AspectJ
asato shimotaki <asatohan at gmail.com>
最終更新日 : 2008/8/2 (2008/8/2 本ページから分割)
AspectJ 基本関連
アスペクトの追加
タイプ:
before:
public class MyClass {
public void method() {
System.out.println("MyClass.method()");
}
}
after:
public class MyClass {
public void method() {
System.out.println("MyClass.method()");
}
}
public aspect MyAspect {
before() : call( void MyClass.method() ) {
System.out.println("before");
}
}
参考文献とリソース
進化パス
パターン関係
関連パターン
参考文献とリソース
todo
抽象アスペクトの導入
タイプ:リファクタリング
before:
public class MyClass {
public void myMethod(String str) {
System.out.println("MyClass.myMethod(String) - " + str);
}
}
public aspect MyAspectA {
before(MyClass my, String str) :
target(my) && args(str) && call(void MyClass.myMethod(String) )
{
System.out.println("before - MyAspectA [" + my + ", " + str + "]");
}
}
public aspect MyAspectB {
before(MyClass my, String str) :
target(my) && args(str) && call(void MyClass.myMethod(String) )
{
System.out.println("before - MyAspectB [" + my + ", " + str + "]");
}
}
after:
public class MyClass {
public void myMethod(String str) {
System.out.println("MyClass.myMethod(String) - " + str);
}
}
public abstract aspect AbstractMyAspect {
before(MyClass my, String str) :
target(my) && args(str) && call(void MyClass.myMethod(String) )
{
log(my, str);
}
protected abstract void log(MyClass my, String str);
}
public aspect MyAspectA extends AbstractMyAspect {
protected void log(MyClass my, String str) {
System.out.println("before - MyAspectA [" + my + ", " + str + "]");
}
}
public aspect MyAspectB extends AbstractMyAspect {
protected void log(MyClass my, String str) {
System.out.println("before - MyAspectB [" + my + ", " + str + "]");
}
}
参考文献とリソース
進化パス
パターン関係
関連パターン
参考文献とリソース
todo
抽象アスペクトの追加
タイプ:
before:
public class MyClass {
public void method() {
System.out.println("MyClass.method()");
}
}
after:
public class MyClass {
public void method() {
System.out.println("MyClass.method()");
}
}
public abstract aspect MyAbstractAspect {
before() : call( void MyClass.method() ) {
primitiveOperation();
}
protected abstract void primitiveOperation();
}
参考文献とリソース
進化パス
パターン関係
関連パターン
参考文献とリソース
todo
サブアスペクトの追加
タイプ:
before:
public class MyClass {
public void method() {
System.out.println("MyClass.method()");
}
}
public abstract aspect MyAbstractAspect {
protected abstract pointcut pc();
before() : pc() {
System.out.println("before");
}
}
public aspect MyAspectA extends MyAbstractAspect {
protected pointcut pc() : call( MyClass.new() );
}
after:
public class MyClass {
public void method() {
System.out.println("MyClass.method()");
}
}
public abstract aspect MyAbstractAspect {
protected abstract pointcut pc();
before() : pc() {
System.out.println("before");
}
}
public aspect MyAspectA extends MyAbstractAspect {
protected pointcut pc() : call( MyClass.new() );
}
public aspect MyAspectB extends MyAbstractAspect {
protected pointcut pc() : call( void MyClass.method() );
}
参考文献とリソース
進化パス
パターン関係
関連パターン
参考文献とリソース
todo
アスペクトからのアスペクトの抽出
タイプ:リファクタリング
before:
public class MyClass {
public void method() {
System.out.println("MyClass.method()");
}
}
public aspect MyAspect {
before() : call(void MyClass.method()) {
System.out.println("MyClass.method() - before");
}
before() : call(* MyClass.*(..)) && !within(MyAspect) {
System.out.println("tracing - before : " + thisJoinPoint);
}
after() : call(* MyClass.*(..)) && !within(MyAspect) {
System.out.println("tracing - after : " + thisJoinPoint);
}
}
after:
public class MyClass { // 変更なし
public void method() {
System.out.println("MyClass.method()");
}
}
public aspect MyAspect {
before() : call(void MyClass.method()) {
System.out.println("MyClass.method() - before");
}
}
public aspect MyClassTracing {
before() : call(* MyClass.*(..)) {
System.out.println("tracing - before : " + thisJoinPoint);
}
after() : call(* MyClass.*(..)) {
System.out.println("tracing - after : " + thisJoinPoint);
}
}
参考文献とリソース
進化パス
パターン関係
関連パターン
参考文献とリソース
todo
アドバイスの追加
タイプ:
before:
public class MyClass {
public void method1() {
System.out.println("MyClass.method1()");
}
public void method2() {
System.out.println("MyClass.method2()");
}
}
public aspect MyAspect {
before() : call(void MyClass.method1()) {
System.out.println("before");
}
}
after:
public class MyClass { // 変更なし
public void method1() {
System.out.println("MyClass.method1()");
}
public void method2() {
System.out.println("MyClass.method2()");
}
}
public aspect MyAspect {
before() : call(void MyClass.method1()) {
System.out.println("before");
}
before() : call(void MyClass.method2()) {
System.out.println("before");
}
}
参考文献とリソース
進化パス
パターン関係
関連パターン
参考文献とリソース
todo
ポイントカット定義の公開
タイプ:
before:
public class MyClass {
public void method() {
System.out.println("MyClass.method()");
}
}
public aspect MyAspect {
private pointcut methodCall() : call( void MyClass.method() );
before() : methodCall() {
System.out.println("before");
}
}
after:
public class MyClass {
public void method() {
System.out.println("MyClass.method()");
}
}
public aspect MyAspect {
public pointcut methodCall() : call( void MyClass.method() );
before() : methodCall() {
System.out.println("before");
}
}
参考文献とリソース
進化パス
パターン関係
関連パターン
参考文献とリソース
todo
アスペクトへのポイントカットの追加
タイプ:
before:
public class MyClass {
public void method() {
System.out.println("MyClass.method()");
}
}
before() : execution(void MyClass.method()) {
printBefore();
}
private void printBefore() {
System.out.println("before");
}
after:
public class MyClass {
public void method() {
System.out.println("MyClass.method()");
}
}
public class MyClass {
public void method() {
System.out.println("MyClass.method()");
}
}
public aspect MyAspect {
public pointcut print() :
call(void MyAspect.printBefore());
before() : execution(void MyClass.method()) {
printBefore();
}
private void printBefore() {
System.out.println("before");
}
}
参考文献とリソース
進化パス
パターン関係
関連パターン
参考文献とリソース
todo
AspectJ 関連
Logging アスペクトの導入
public class Component {
private int param1;
private int param2;
public void setParameter1(int param1) {
this.param1 = param1;
}
public void setParameter2(int param2) {
this.param2 = param2;
}
}
public class Main {
public static void main(String[] args) throws Exception {
int param1 = 5;
int param2 = 10;
PrintWriter log = new PrintWriter(new FileWriter("log.txt"), true);
log.println("param1 = " + param1);
log.println("param2 = " + param2);
Component comp = new Component();
comp.setParameter1(param1);
comp.setParameter2(param2);
}
}
after:
public class Component { // 変更なし
private int param1;
private int param2;
public void setParameter1(int param1) {
this.param1 = param1;
}
public void setParameter2(int param2) {
this.param2 = param2;
}
}
public aspect ParameterLogging {
private PrintWriter log;
public ParameterLogging() {
try {
this.log = new PrintWriter(new FileWriter("log.txt"), true);
} catch(IOException e) {
throw new RuntimeException(e);
}
}
before(int param1) :
args(param1) && call(void Component.setParameter1(int))
{
log.println("param1 = " + param1);
}
before(int param2) :
args(param2) && call(void Component.setParameter2(int))
{
log.println("param2 = " + param2);
}
}
public class Main {
public static void main(String[] args) throws Exception {
Component comp = new Component();
comp.setParameter1(5);
comp.setParameter2(10);
}
}
Activation 機能の導入
public class Component {
public void method() {
System.out.println("Component.method()");
}
}
public aspect ComponentAspect {
before() : call( void Component.method() ) {
System.out.println("before");
}
}
public class Main {
public static void main(String[] args) {
Component comp = new Component();
comp.method();
}
}
実行結果:
before Component.method()after:
public class Component {
public void method() {
System.out.println("Component.method()");
}
}
public aspect ComponentAspect {
private static boolean isActive = true;
public void activate() {
isActive = true;
}
public void deactivate() {
isActive = false;
}
before() : call( void Component.method() ) && if(isActive) {
System.out.println("before");
}
}
public class Main {
public static void main(String[] args) {
Component comp = new Component();
comp.method();
ComponentAspect.aspectOf().deactivate();
comp.method();
}
}
実行結果:
before Component.method() Component.method()
アスペクトによるパラメータの置き換え
public class Main {
public static void main(String[] args) {
runProgram("defalut"); // ここを直接修正してモードを設定
}
public static void runProgram(String mode) {
if (mode.equals("verbose")) {
System.out.println("verbose mode");
} else {
System.out.println("defalut mode");
}
}
}
実行結果:
defalut modeafter:
public class Main {
public static void main(String[] args) {
runProgram("defalut");
}
public static void runProgram(String mode) {
if (mode.equals("verbose")) {
System.out.println("verbose mode");
} else {
System.out.println("defalut mode");
}
}
}
public aspect ModeAspect {
void around(String mode) :
args(mode) && call( void Main.runProgram(String) )
{
proceed("verbose"); // ここで間接的に修正してモードを設定
}
}
実行結果:
verbose mode
inter-type 宣言による Marker interface の実装
public class ComponentA {
public void method() {
System.out.println("ComponentA.method()");
}
}
public aspect MyAspect {
before() : call( void ComponentA.method() ) {
System.out.println("before");
}
}
after:
public class ComponentA {
public void method() {
System.out.println("ComponentA.method()");
}
}
public class ComponentB {
public void method() {
System.out.println("ComponentB.method()");
}
}
public aspect MyAspect {
interface ComponentInterface {
public void method();
}
declare parents : ComponentA implements ComponentInterface;
declare parents : ComponentB implements ComponentInterface;
before() : call( void ComponentInterface.method() ) {
System.out.println("before");
}
}
inter-type 宣言による Marker interface の実装の抽出
public class ComponentA {
public void method() {
System.out.println("ComponentA.method()");
}
}
public class ComponentB {
public void method() {
System.out.println("ComponentB.method()");
}
}
public aspect MyAspect {
interface ComponentInterface {
public void method();
}
declare parents : ComponentA implements ComponentInterface;
declare parents : ComponentB implements ComponentInterface;
before() : call( void ComponentInterface.method() ) {
System.out.println("MyAspect - before");
}
}
public aspect YourAspect {
interface ComponentInterface {
public void method();
}
declare parents : ComponentA implements ComponentInterface;
declare parents : ComponentB implements ComponentInterface;
before() : call( void ComponentInterface.method() ) {
System.out.println("YourAspect - before");
}
}
after:
public class ComponentA {
public void method() {
System.out.println("ComponentA.method()");
}
}
public class ComponentB {
public void method() {
System.out.println("ComponentB.method()");
}
}
public interface ComponentInterface {
public void method();
}
public aspect ComponentInterfaceDeclareParents {
declare parents : ComponentA implements ComponentInterface;
declare parents : ComponentB implements ComponentInterface;
}
public aspect MyAspect {
before() : call( void ComponentInterface.method() ) {
System.out.println("MyAspect - before");
}
}
public aspect YourAspect {
before() : call( void ComponentInterface.method() ) {
System.out.println("YourAspect - before");
}
}
inter-type 宣言による Marker interface の実装 - コンポーネントの追加
public class ComponentA {
public void method() {
System.out.println("ComponentA.method()");
}
}
public class ComponentB {
public void method() {
System.out.println("ComponentB.method()");
}
}
public interface ComponentInterface {
public void method();
}
public aspect ComponentInterfaceDeclareParents {
declare parents : ComponentA implements ComponentInterface;
declare parents : ComponentB implements ComponentInterface;
}
public aspect MyAspect {
before() : call( void ComponentInterface.method() ) {
System.out.println("MyAspect - before");
}
}
public aspect YourAspect {
before() : call( void ComponentInterface.method() ) {
System.out.println("YourAspect - before");
}
}
after:
public class ComponentA {
public void method() {
System.out.println("ComponentA.method()");
}
}
public class ComponentB {
public void method() {
System.out.println("ComponentB.method()");
}
}
public class ComponentC {
public void method() {
System.out.println("ComponentC.method()");
}
}
public interface ComponentInterface {
public void method();
}
public aspect ComponentInterfaceDeclareParents {
declare parents : ComponentA implements ComponentInterface;
declare parents : ComponentB implements ComponentInterface;
declare parents : ComponentC implements ComponentInterface;
}
public aspect MyAspect {
before() : call( void ComponentInterface.method() ) {
System.out.println("MyAspect - before");
}
}
public aspect YourAspect {
before() : call( void ComponentInterface.method() ) {
System.out.println("YourAspect - before");
}
}
todo
or pointcut の追加
public class MyClass {
public void myMethod() {
System.out.println("MyClass.myMethod()");
}
}
public aspect CommonPointcuts {
public pointcut methodExecution() :
execution( void MyClass.myMethod() );
}
public aspect Logging {
before() : CommonPointcuts.methodExecution() {
System.out.println("before");
}
}
after:
public class MyClass { // 変更なし
public void myMethod() {
System.out.println("MyClass.myMethod()");
}
}
public class YourClass {
public void yourMethod() {
System.out.println("YourClass.yourMethod()");
}
}
public aspect CommonPointcuts {
public pointcut methodExecution() :
execution( void MyClass.myMethod() ) ||
execution( void YourClass.yourMethod() );
}
public aspect Logging { // 変更なし
before() : CommonPointcuts.methodExecution() {
System.out.println("before");
}
}
todo
重複するポイントカットの移動
public class Component {
public void method() {
System.out.println("Component.method()");
}
}
public aspect MyAspect {
before() : call( void Component.method() ) {
System.out.println("MyAspect - before");
}
}
after:
public class Component { // 変更なし
public void method() {
System.out.println("Component.method()");
}
}
public aspect ComponentPointcuts {
public pointcut callMethod() : call( void Component.method() );
}
public aspect MyAspect {
before() : ComponentPointcuts.callMethod() {
System.out.println("MyAspect - before");
}
}
public aspect YourAspect {
before() : ComponentPointcuts.callMethod() {
System.out.println("YourAspect - before");
}
}
進化パス
関連パターン
参考文献とリソース
todo
ジョインポイントリスナーの追加
public class Component {
public void method() {
new ComponentJoinPoint();
}
}
public class ComponentJoinPoint {
}
public aspect MyAspect {
before() : call( ComponentJoinPoint.new() ) {
System.out.println("MyAspect - before");
}
}
after:
public class Component { // 変更なし
public void method() {
new ComponentJoinPoint();
}
}
public class ComponentPointcuts {
public pointcut componentJoinPoint() : call( ComponentJoinPoint.new() );
}
public aspect MyAspect {
before() : ComponentPointcuts.componentJoinPoint() {
System.out.println("MyAspect - before");
}
}
public aspect YourAspect {
before() : ComponentPointcuts.componentJoinPoint() {
System.out.println("YourAspect - before");
}
}
進化パス
関連パターン
参考文献とリソース
todo
メソッド名変更によるポイントカット定義の修正
タイプ:
before:
public class AlgorithmRunner {
public void runMyAlgorithm() {
new MyClass().myMethod();
}
}
public class MyClass {
public void myMethod() {
System.out.println("MyClass.myMethod()");
}
}
public aspect MyAspect {
before() :
withincode( void AlgorithmRunner.runMyAlgorithm() ) &&
call(void MyClass.myMethod() )
{
System.out.println("MyAspect - before");
}
}
public class Main {
public static void main(String[] args) {
new AlgorithmRunner().runMyAlgorithm();
}
}
after:
public interface Algorithm {
public void run();
}
public class AlgorithmRunner {
private List algorithms = new ArrayList();
public void addAlgorithm(Algorithm algorithm) {
algorithms.add(algorithm);
}
public void run() {
for(Iterator itr = algorithms.iterator(); itr.hasNext();) {
( (Algorithm)itr.next() ).run();
}
}
}
public class MyClass {
public void myMethod() {
System.out.println("MyClass.myMethod()");
}
}
public class MyAlgorithm implements Algorithm {
public void run() {
new MyClass().myMethod();
}
}
public aspect MyAspect {
before() :
withincode( void MyAlgorithm.run() ) &&
call(void MyClass.myMethod() )
{
System.out.println("MyAspect - before");
}
}
public class Main {
public static void main(String[] args) {
AlgorithmRunner runner = new AlgorithmRunner();
runner.addAlgorithm( new MyAlgorithm() );
runner.run();
}
}
進化パス
関連パターン
参考文献とリソース
todo
重複するポイントカット定義の追加
タイプ:
before:
public class Component {
private String name;
public void method() {
System.out.println("Component.method()");
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
public aspect ComponentPointcuts {
public pointcut callMethod() : call( void Component.method() );
}
public aspect MyAspect {
before() : ComponentPointcuts.callMethod() {
System.out.println("MyAspect - method() - before");
}
}
public aspect YourAspect {
before() : ComponentPointcuts.callMethod() {
System.out.println("YourAspect - method() - before");
}
}
public class Main {
public static void main(String[] args) {
Component comp = new Component();
comp.method();
comp.setName("xxx");
}
}
after:
public class Component { // 変更なし
private String name;
public void method() {
System.out.println("Component.method()");
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
public aspect ComponentPointcuts {
public pointcut callMethod() : call( void Component.method() );
public pointcut callSetName() : call( void Component.setName(String) );
}
public aspect MyAspect {
before() : ComponentPointcuts.callMethod() {
System.out.println("MyAspect - method() - before");
}
before() : ComponentPointcuts.callSetName() {
System.out.println("MyAspect - setName(String) - before");
}
}
public aspect YourAspect {
before() : ComponentPointcuts.callMethod() {
System.out.println("YourAspect - method() - before");
}
before() : ComponentPointcuts.callSetName() {
System.out.println("YourAspect - setName(String) - before");
}
}
public class Main { // 変更なし
public static void main(String[] args) {
Component comp = new Component();
comp.method();
comp.setName("xxx");
}
}
進化パス
関連パターン
参考文献とリソース
todo
tangled code の抽出
タイプ:Transient Refactoring
before:
public class Main {
public static void main(String[] args) {
tangledCode();
mainCode();
}
private static void tangledCode() {
System.out.println("tangled code");
}
private static void mainCode() {
System.out.println("main code");
}
}
after:
public class Main {
public static void main(String[] args) {
mainCode();
}
private static void mainCode() {
System.out.println("main code");
}
}
public aspect TangledCodeAspect {
before() : execution(void Main.main(String[])) {
System.out.println("tangled code");
}
}
サンプルコード:LookAndFeel の初期化
public class Main {
public static void main(String[] args) {
initLookAndFeel(); // tangled code
run(); // main code
}
private static void initLookAndFeel() { // tangledCode()
try {
UIManager.setLookAndFeel( UIManager.getSystemLookAndFeelClassName() );
} catch(Exception e) { }
}
private static void run() { // mainCode()
JFrame f = new JFrame("test");
JPanel pane = new JPanel();
pane.add( new JButton("ok") );
f.getContentPane().add(pane);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.pack();
f.setVisible(true);
}
}
after:
public class Main {
public static void main(String[] args) {
run();
}
private static void run() {
JFrame f = new JFrame("test");
JPanel pane = new JPanel();
pane.add( new JButton("ok") );
f.getContentPane().add(pane);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.pack();
f.setVisible(true);
}
}
public aspect LookAndFeelInitialization {
before() : execution(void Main.main(String[])) {
try {
UIManager.setLookAndFeel( UIManager.getSystemLookAndFeelClassName() );
} catch(Exception e) {}
}
}
もし、AspectJ 5 を使っているのであれば、アノテーションを用いた方が依存がより小さくなります。
public @interface LookAndFeelInit { }
public aspect LookAndFeelInitialization {
before() : execution(@LookAndFeelInit * *(..)) {
try {
UIManager.setLookAndFeel( UIManager.getSystemLookAndFeelClassName() );
} catch(Exception e) {}
}
}
public class Main {
@LookAndFeelInit
public static void main(String[] args) {
run();
}
private static void run() {
JFrame f = new JFrame("test");
JPanel pane = new JPanel();
pane.add( new JButton("ok") );
f.getContentPane().add(pane);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.pack();
f.setVisible(true);
}
}
参考文献とリソース
進化パス
パターン関係
関連パターン
参考文献とリソース
todo
Event Tracing の導入
タイプ:Refactoring
before:
public interface ComponentListener {
public void methodAEntered();
public void methodBEntered();
}
public class Component {
private List listeners = new ArrayList();
public void addListener(ComponentListener l) {
listeners.add(l);
}
public void removeListener(ComponentListener l) {
listeners.remove(l);
}
public void methodA() {
fireMethodAEntered();
System.out.println("Component.methodA()");
}
public void methodB() {
fireMethodBEntered();
System.out.println("Component.methodB()");
}
private void fireMethodAEntered() {
for(ComponentListener l : listeners) {
l.methodAEntered();
}
}
private void fireMethodBEntered() {
for(ComponentListener l : listeners) {
l.methodBEntered();
}
}
}
public class ComponentMethodCounter implements ComponentListener {
private int methodA = 0;
private int methodB = 0;
public void methodAEntered() {
System.out.println("entered : method A");
methodA++;
}
public void methodBEntered() {
System.out.println("entered : method B");
methodB++;
}
}
after:
public interface ComponentListener { // 変更なし
public void methodAEntered();
public void methodBEntered();
}
public class Component { // 変更なし
private List listeners = new ArrayList();
public void addListener(ComponentListener l) {
listeners.add(l);
}
public void removeListener(ComponentListener l) {
listeners.remove(l);
}
public void methodA() {
fireMethodAEntered();
System.out.println("Component.methodA()");
}
public void methodB() {
fireMethodBEntered();
System.out.println("Component.methodB()");
}
private void fireMethodAEntered() {
for(ComponentListener l : listeners) {
l.methodAEntered();
}
}
private void fireMethodBEntered() {
for(ComponentListener l : listeners) {
l.methodBEntered();
}
}
}
public class ComponentMethodCounter implements ComponentListener {
private int methodA = 0;
private int methodB = 0;
public void methodAEntered() {
methodA++;
}
public void methodBEntered() {
methodB++;
}
}
public aspect EventTracing {
before () : execution(* ComponentListener.*(..) ) {
System.out.println("enter " + thisJoinPoint.getSignature().getName());
}
}
サンプルコード
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
public class KeyCounter implements KeyListener {
private int pressed;
private int released;
private int typed;
public void keyPressed(KeyEvent e) {
pressed++;
}
public void keyReleased(KeyEvent e) {
released++;
}
public void keyTyped(KeyEvent e) {
typed++;
}
// その他のメソッド
}
public aspect EventTracing {
before () : execution(* java.awt.event.KeyListener.*(..) ) {
System.out.println("enter " + thisJoinPoint.getSignature().getName());
}
}
public class Main {
public static void main(String[] args) {
JPanel pane = new JPanel();
pane.addKeyListener(new KeyCounter());
pane.setFocusable(true);
JFrame frame = new JFrame("test");
frame.getContentPane().add(pane);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
}
参考文献とリソース
進化パス
パターン関係
関連パターン
参考文献とリソース
todo
トレースされる Event Listener の追加
タイプ:
before:
public interface ComponentListener {
public void methodAEntered();
public void methodBEntered();
}
public class Component {
private List listeners = new ArrayList();
public void addListener(ComponentListener l) {
listeners.add(l);
}
public void removeListener(ComponentListener l) {
listeners.remove(l);
}
public void methodA() {
fireMethodAEntered();
System.out.println("Component.methodA()");
}
public void methodB() {
fireMethodBEntered();
System.out.println("Component.methodB()");
}
private void fireMethodAEntered() {
for(ComponentListener l : listeners) {
l.methodAEntered();
}
}
private void fireMethodBEntered() {
for(ComponentListener l : listeners) {
l.methodBEntered();
}
}
}
public class ComponentMethodCounter implements ComponentListener {
private int methodA = 0;
private int methodB = 0;
public void methodAEntered() {
methodA++;
}
public void methodBEntered() {
methodB++;
}
}
public aspect EventTracing {
before () : execution(* ComponentListener.*(..) ) {
System.out.println("enter " + thisJoinPoint.getSignature().getName());
}
}
after:
public interface ComponentListener { // 変更なし
public void methodAEntered();
public void methodBEntered();
}
public class Component { // 変更なし
private List listeners = new ArrayList();
public void addListener(ComponentListener l) {
listeners.add(l);
}
public void removeListener(ComponentListener l) {
listeners.remove(l);
}
public void methodA() {
fireMethodAEntered();
System.out.println("Component.methodA()");
}
public void methodB() {
fireMethodBEntered();
System.out.println("Component.methodB()");
}
private void fireMethodAEntered() {
for(ComponentListener l : listeners) {
l.methodAEntered();
}
}
private void fireMethodBEntered() {
for(ComponentListener l : listeners) {
l.methodBEntered();
}
}
}
public class ComponentMethodCounter implements ComponentListener { // // 変更なし
private int methodA = 0;
private int methodB = 0;
public void methodAEntered() {
methodA++;
}
public void methodBEntered() {
methodB++;
}
}
public interface MyClassListener {
public void myMethodAInvoked();
public void myMethodBInvoked();
}
public class MyClass {
private List listeners = new ArrayList();
public void addListener(MyClassListener l) {
listeners.add(l);
}
public void removeListener(MyClassListener l) {
listeners.remove(l);
}
public void myMethodA() {
fireMyMethodAInvoked();
System.out.println("Component.methodA()");
}
public void myMethodB() {
fireMyMethodBInvoked();
System.out.println("Component.methodB()");
}
private void fireMyMethodAInvoked() {
for(MyClassListener l : listeners) {
l.myMethodAInvoked();
}
}
private void fireMyMethodBInvoked() {
for(MyClassListener l : listeners) {
l.myMethodBInvoked();
}
}
}
public class MyClassMethodCounter implements MyClassListener {
private int myMethodA = 0;
private int myMethodB = 0;
public void myMethodAInvoked() {
myMethodA++;
}
public void myMethodBInvoked() {
myMethodB++;
}
// その他のメソッド
}
public aspect EventTracing {
private pointcut tracedEvent() :
execution(* ComponentListener.*(..) ) ||
execution(* MyClassListener.*(..) );
before () : tracedEvent() {
System.out.println("enter " + thisJoinPoint.getSignature().getName());
}
}
サンプルコード
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
public class KeyCounter implements KeyListener {
private int pressed;
private int released;
private int typed;
public void keyPressed(KeyEvent e) {
pressed++;
}
public void keyReleased(KeyEvent e) {
released++;
}
public void keyTyped(KeyEvent e) {
typed++;
}
// その他のメソッド
}
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
public class MouseCounter implements MouseListener {
private int clicked;
private int entered;
private int exited;
private int pressed;
private int released;
public void mouseClicked(MouseEvent e) {
clicked++;
}
public void mouseEntered(MouseEvent e) {
entered++;
}
public void mouseExited(MouseEvent e) {
exited++;
}
public void mousePressed(MouseEvent e) {
pressed++;
}
public void mouseReleased(MouseEvent e) {
released++;
}
}
public aspect EventTracing {
private pointcut tracedEvent() :
execution(* java.awt.event.KeyListener.*(..) ) ||
execution(* java.awt.event.MouseListener.*(..) );
before () : tracedEvent() {
System.out.println("enter " + thisJoinPoint.getSignature().getName());
}
}
public class Main {
public static void main(String[] args) {
JPanel pane = new JPanel();
pane.addKeyListener(new KeyCounter());
pane.addMouseListener(new MouseCounter());
pane.setFocusable(true);
JFrame frame = new JFrame("test");
frame.getContentPane().add(pane);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
}
参考文献とリソース
進化パス
関連パターン
参考文献とリソース
todo
ポイントカットアスペクト - アスペクトの追加
タイプ:機能追加
before:
public class Component {
public void method() {
System.out.println("Component.method()");
}
}
public aspect ComponentPointcuts {
public pointcut callMethod() : call( void Component.method() );
}
public aspect MyAspectA {
before() : ComponentPointcuts.callMethod() {
System.out.println("MyAspectA - before");
}
}
public aspect MyAspectB {
before() : ComponentPointcuts.callMethod() {
System.out.println("MyAspectB - before");
}
}
after:
public class Component {
public void method() {
System.out.println("Component.method()");
}
}
public aspect ComponentPointcuts {
public pointcut callMethod() : call( void Component.method() );
}
public aspect MyAspectA {
before() : ComponentPointcuts.callMethod() {
System.out.println("MyAspectA - before");
}
}
public aspect MyAspectB {
before() : ComponentPointcuts.callMethod() {
System.out.println("MyAspectB - before");
}
}
public aspect MyAspectC {
before() : ComponentPointcuts.callMethod() {
System.out.println("MyAspectC - before");
}
}
参考文献とリソース
進化パス
パターン関係
関連パターン
参考文献とリソース
todo
アスペクトへのコンテキストアノテーションの付加
タイプ:
before:
public class MyClass {
public void myMethod() {
System.out.println("MyClass.myMethod()");
}
}
public class YourClass {
public void yourMethod() {
System.out.println("YourClass.yourMethod()");
}
}
public aspect MyAspect {
before() : call(void MyClass.myMethod()) {
System.out.println("MyAspect");
new YourClass().yourMethod();
}
}
after:
public class MyClass {
public void myMethod() {
System.out.println("MyClass.myMethod()");
}
}
public class YourClass {
public void yourMethod() {
System.out.println("YourClass.yourMethod()");
}
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface ContextAnnotation {
public String value();
}
public aspect ContextAnnotationAspect {
before(ContextAnnotation context) :
@within(context) && call(void YourClass.yourMethod())
{
System.out.println(context.value());
}
}
@ContextAnnotation("MyAspect")
public aspect MyAspect {
before() : call(void MyClass.myMethod()) {
new YourClass().yourMethod();
}
}
参考文献とリソース
進化パス
パターン関係
関連パターン
参考文献とリソース
todo
Template Advice - Concrete Aspect の追加
タイプ:
before:
public class MyClass {
public void method() {
System.out.println("MyClass.method()");
}
}
public abstract aspect MyAbstractAspect {
before() : call( void MyClass.method() ) {
primitiveOperation();
}
protected abstract void primitiveOperation();
}
public aspect MyConcreteAspectA extends MyAbstractAspect {
protected void primitiveOperation() {
System.out.println("MyConcreteAspectA.primitiveOperation()");
}
}
after:
public class MyClass {
public void method() {
System.out.println("MyClass.method()");
}
}
public abstract aspect MyAbstractAspect {
before() : call( void MyClass.method() ) {
primitiveOperation();
}
protected abstract void primitiveOperation();
}
public aspect MyConcreteAspectA extends MyAbstractAspect {
protected void primitiveOperation() {
System.out.println("MyConcreteAspectA.primitiveOperation()");
}
}
public aspect MyConcreteAspectB extends MyAbstractAspect {
protected void primitiveOperation() {
System.out.println("MyConcreteAspectB.primitiveOperation()");
}
}
参考文献とリソース
進化パス
パターン関係
関連パターン
参考文献とリソース
todo
アノテーションによる interface の実装
タイプ:
before:
public interface MyInterface {
}
public aspect MyInterfaceImplementation {
public void MyInterface.method() {
System.out.println("method");
}
}
public class MyClass implements MyInterface {
}
after:
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface MyAnnotation {
}
public interface MyInterface {
}
public aspect MyInterfaceImplementation {
public void MyInterface.method() {
System.out.println("method");
}
}
public aspect MyAspect {
declare parents : (@MyAnnotation *) implements MyInterface;
}
@MyAnnotation
public class MyClass {
}
参考文献とリソース
進化パス
パターン関係
関連パターン
参考文献とリソース
todo
参考文献とリソース
更新履歴
todo