JavaでMix-inっぽいことをやってみた

必要に駆られて作ってみたけれど、例としてはイマイチな気がする。
参考:Java : Mixin(多重継承)とかパーシャルクラスとか - lethevert is a programmer

矢印は実装の継承の方向。

JFrame extends Window
JDialog extends Window
これら2つのクラスに対して同様の拡張を行ないたい場合、
A extends JFrame
B extends JDialog
を作ってそれぞれに同じコードを書く必要があるのだけれど、それを無理やり共通化してしまおうという試み。

ソースコード

import java.awt.Window;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JOptionPane;

public class MixinTest {
	public static void main(String[] args) throws Exception {
		new A();
		new B();
	}
}

class A extends JFrame implements ActionListener {
	Mixin mixin = new Mixin() {
		public Window getWindow() {
			return A.this;
		}
		public String getVersion() {
			return A.this.version;
		}
	};
	
	public String version = "1.00";
	JButton button; 
	public A() {
		super();
		mixin.initialize(0, 0, 300, 200);
		button = mixin.addButton("foo", 10, 0, 100, 20);
		setVisible(true);
	}
	@Override
	public void actionPerformed(ActionEvent event) {
		Object src = event.getSource();
		if (src.equals(button)) {
			mixin.showMessageDialog("message!");
		}
	}
}
class B extends JDialog {
	Mixin mixin = new Mixin() {
		public Window getWindow() {
			return B.this;
		}
	};
	
	public B() {
		super();
		mixin.initialize(20, 200, 200, 100);
		mixin.addButton("baa", 10, 30, 100, 20);
		setVisible(true);
	}
}
abstract class Mixin {
	abstract public Window getWindow();
	public String getVersion() {
		return null;
	}
	
	public void initialize(int x, int y, int w, int h) {
		Window window = getWindow();
		window.setLayout(null);
		window.setBounds(x, y, w, h);
	}
	
	public JButton addButton(String text, int x, int y, int w, int h) {
		Window window = getWindow();
		JButton button = new JButton(text);
		button.setBounds(x, y, w, h);
		if (window instanceof ActionListener) {
			button.addActionListener((ActionListener)window);
		}
		window.add(button);
		return button;
	}
	
	public void showMessageDialog(String message) {
		String version = getVersion();
		if (version != null) {
			message += "\nversion " + getVersion();
		}
		JOptionPane.showMessageDialog(getWindow(), message);
	}
}

結果(fooボタンを押したところ)

MixinクラスのコンストラクタでWindowインスタンスとバージョンを渡せば同様のことはできそうだが、このやり方ならば例えばA#versionの値がどこかで変化した場合にMixinクラスに対してそれを通知する必要が無い。Mixinクラスに対して値ではなく参照(?)を渡しているからだ。