AspectJ を使ったデザインパターンの改善と支援 >
Decorator

最終更新日 : 2003/4/1
asato <asato@ncfreak.com>

index > decorator

オブジェクトの同一性を意識した Decorator の実装

意図: オブジェクトの同一性を保ちつつオブジェクトに動的に責任を追加する。

問題: GoF のデザインパターンでは、装飾されるオブジェクトと装飾された後のオブジェクトを、同じオブジェクトとして扱うことができない。

適用可能性:

結果 (利点):

結果 (欠点):

サンプルコード (実装例その1。その 2 は下のほうを参照):

package dp.decorator;

public class ConcreteStringComponent {

	private String str;

	public ConcreteStringComponent(String str) {
		this.str = str;
	}
	public String getString() {
		return str;
	}
}
package dp.decorator;

public interface StringComponent { }
package dp.decorator;

public class ConcreteDecoratorA {

	public String getString() {
		StringComponent comp = getComponent();

		return "[ " + comp.getString() + " ]";
	}
}
package dp.decorator;

public class ConcreteDecoratorB {

	public String getString() {
		StringComponent comp = getComponent();

		return "***" + comp.getString() + "***";
	}
}
package dp;

import dp.decorator.*;

public class Client {

	public static void main(String[] args) {

		StringComponent comp = new ConcreteStringComponent("aaa");

		System.out.println( comp.getString() ); // aaa


		StringComponentDecorator.decorate(comp, new ConcreteDecoratorA() );

		System.out.println( comp.getString() ); // [ aaa ]


		StringComponentDecorator.decorate(comp, new ConcreteDecoratorB() );

		System.out.println( comp.getString() ); // *** [ aaa ] ***


		StringComponentDecorator.decorate(comp, new ConcreteDecoratorA() );

		System.out.println( comp.getString() ); // [ *** [ aaa ] *** ]
	}
}
package dp;

import java.util.Map;
import java.util.HashMap;

public aspect StringComponentDecorator {

	private static Map decorationMap = new HashMap();

	declare parents : ConcreteStringComponent implements StringComponent;
	declare parents : StringComponentConcreteDecorator implements StringComponent;

	declare parents : ConcreteDecoratorA implements StringComponentConcreteDecorator;
	declare parents : ConcreteDecoratorB implements StringComponentConcreteDecorator;

	public interface StringComponentConcreteDecorator { }


	private StringComponent StringComponentConcreteDecorator.component;

	public StringComponent StringComponentConcreteDecorator.getComponent() {
		return component;
	}
	private void StringComponentConcreteDecorator.setComponent(StringComponent component) {
		this.component = component;
	}


	public abstract String StringComponent.getString();

	public static void decorate(StringComponent component, StringComponentConcreteDecorator decorator) {
		if ( getDecorator(component) == null) {
			decorator.setComponent( component );
		} else {
			decorator.setComponent( getDecorator(component) );
		}
		decorationMap.put(component, decorator);
	}

	private static StringComponentConcreteDecorator getDecorator(StringComponent component) {
		return (StringComponentConcreteDecorator)decorationMap.get(component);
	}

	pointcut componentObj(ConcreteStringComponent component) :
		this(component) &&
		!cflow( this(StringComponentConcreteDecorator+) ) &&
		if ( getDecorator(component) != null );


	pointcut getString(ConcreteStringComponent component) :
		componentObj(component) &&
		execution( String ConcreteStringComponent.getString() );

	Object around(StringComponent component) : getString(component) {
		return getDecorator(component).getString();
	}
}
aaa
[ aaa ]
*** [ aaa ] ***
[ *** [ aaa ] *** ]

実装:

サンプルコード (実装例その 2):
package dp;

import dp.decorator.*;

public class Client {

	public static void main(String[] args) {

		StringComponent comp = new ConcreteStringComponent("aaa");

		System.out.println( comp.getString() ); // aaa


		Decorator.decorate(comp, new ConcreteDecoratorA() );

		System.out.println( comp.getString() ); // [ aaa ]


		Decorator.decorate(comp, new ConcreteDecoratorB() );

		System.out.println( comp.getString() ); // *** [ aaa ] ***
	}
}
package dp.decorator;

public class Decorator { }
package dp.decorator;

import java.util.Map;
import java.util.HashMap;

public abstract aspect DecoratorProtocol {

	private Map decorationMap = new HashMap();
	private Map pairMap       = new HashMap();


	abstract pointcut callGetComponent();

	pointcut getComponent(Object decorator) :
		target(decorator) && callGetComponent();

	Object around(Object decorator) : getComponent(decorator) {
		return pairMap.get(decorator);
	}

	protected void decorate(Object component, Object decorator) {

		if ( getDecorator(component) == null) {
			pairMap.put(decorator, component);
		} else {
			pairMap.put(decorator, getDecorator(component));
		}

		decorationMap.put(component, decorator);
	}

	protected Object getDecorator(Object component) {
		return decorationMap.get(component);
	}
}
package dp.decorator;

public aspect StringComponentAspect extends DecoratorProtocol {

	declare parents : ConcreteStringComponent implements StringComponent;
	declare parents : StringComponentDecorator implements StringComponent;

	declare parents : ConcreteDecoratorA implements StringComponentDecorator;
	declare parents : ConcreteDecoratorB implements StringComponentDecorator;

	protected interface StringComponentDecorator { }


	public static void Decorator.decorate(StringComponent component, StringComponentDecorator decorator) {
		StringComponentAspect.aspectOf().decorate(component, decorator);
	}

	public StringComponent StringComponentDecorator.getComponent() {
		throw new RuntimeException("implementation error");
	}

	public abstract String StringComponent.getString();


	pointcut callGetComponent() :
		call(StringComponent StringComponentDecorator.getComponent() );


	pointcut componentObj(ConcreteStringComponent component) :
		this(component) &&
		!cflow( this(StringComponentDecorator+) ) &&
		if ( StringComponentAspect.aspectOf().getDecorator(component) != null );

	pointcut getString(ConcreteStringComponent component) :
		componentObj(component) &&
		execution( String ConcreteStringComponent.getString() );

	Object around(StringComponent component) : getString(component) {
		return getDecorator(component).getString();
	}

	private StringComponentDecorator getDecorator(StringComponent component) {
		return (StringComponentDecorator)super.getDecorator(component);
	}
}
実装:

更新履歴

index > decorator