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 アスペクトの導入

before:
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 機能の導入

before:

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()

アスペクトによるパラメータの置き換え

before:

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 mode
after:
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 の実装

before:

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 の実装の抽出

before:

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 の実装 - コンポーネントの追加

before:

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 の追加

before:

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

重複するポイントカットの移動

before:

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

ジョインポイントリスナーの追加

before:

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 の初期化

before:

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