Mixin的なもの

普段使いのRubyでは、ModuleのMixinによって実装の継承ができて大変嬉しいのですが、Javaの場合はできなさそうで少し悲しいなぁ、と思っていたところSpring AOPをつかうとそれっぽいことができそうなので試してみました。

まず、Mixinのことなど何も知らないUserクラスがあるとします。nameしか情報を持っていません。

package com.hoge;

public class User {
	private String name;
	
	public void setName(String name) {
		this.name = name;
	}

	public String getName() {
		return name;
	}
}

で、これに年齢に関する機能をつけたい場合、Spring AOPのIntroductionを使って、Ageインターフェースと...

package com.hoge;

public interface Age {
	void setAge(int age);
	int getAge();
}

AgeMixinクラスを作ります。

package com.hoge;

import org.springframework.aop.support.
       DelegatingIntroductionInterceptor;

public class AgeMixin extends DelegatingIntroductionInterceptor
		implements Age {

	private static final long serialVersionUID = 1L;
	private int age;

	@Override
	public int getAge() {
		return age;
	}

	@Override
	public void setAge(int age) {
		this.age = age;
	}
}

で、これらをくっつけます。

package com.hoge;

import org.springframework.aop.framework.ProxyFactory;
import org.springframework.aop.support.
       DefaultIntroductionAdvisor;

public class Main {
	public static void main(String[] args) {
		ProxyFactory beanFactory = 
			new ProxyFactory(new Class[] { Age.class });
		beanFactory.setProxyTargetClass(true);
		beanFactory.addAdvisor(
                        new DefaultIntroductionAdvisor(new AgeMixin()));
		beanFactory.setTarget(new User());

		User user = (User) beanFactory.getProxy();
		user.setName("komamitsu");
		System.out.println(user.getName());

		((Age) user).setAge(18);
		System.out.println(((Age) user).getAge());
	}
}

setAge()を呼ぶときにAgeクラスにキャストしているところが悲しいですが、気を取り直して実行してみると...

komamitsu
18

と表示され、Ageの(set|get)Age()が使えているのが分かります。RubyのModuleと異なり、Mixin用のクラスは継承可能なので、もしかしたら何か嬉しいかも知れません。