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