I am using the following technique for simulating mixins (or Traits) using Java and would like to know whether this is reasonable or just confusing to future developers. Also, I believe a good naming scheme is the best documentation, so if it would help to change the nomenclature, please provide suggestions.
/** A mixin interface which your class should implement */
public interface IsResizableMixin {
/**
* The implementation, which your class should
* instance and delegate calls to
*/
public static class IsResizableMixinImpl implements IsResizableMixin {
// A widget is e.g. a Swing Component, a GWT Widget, etc.
private Widget w;
pubic IsResizableMixinImpl(Widget w) {
this.w = w;
}
public void resizeTo(int width, int height);
/* for example */
w.setWidth(width);
w.setHeight(height);
w.getParent().redraw();
}
}
void resizeTo(int width, int height);
}
Then an example implementation of a Widget
, one that is resizable:
public class Foo extends Widget implements IsResizableMixin { private IsResizableMixin mixin; /* ... */ public Foo() { super(); this.mixin = new IsResizableMixinImpl(this); /* ... */ } /* ... */ public void resizeTo(int w, int h) { mixin.resizeTo(w, h); } }
A richer example would be a Widget
that can be set "busy", that is, overlaid with a spinner and disabled.
public interface IsBusyMixin { public class IsBusyMixinImpl implements IsBusyMixin { private Widget w; private boolean isBusy = false; pubic IsBusyMixinImpl(Widget w) { this.w = w; } public void toggleBusy(); isBusy = !isBusy(); if (isBusy) { /* overlay the component with a spinner */ } else { /* remove the spinner overlay */ } } } void toggleBusy(); } public class Foo extends Widget implements IsBusyMixin { // Other than the fact that this method exists, // Foo is unaware that it can be toggled to a busy state. public void toggleBusy() { this.mixin.toggleBusy(); } }
The benefits of this approach are:
- Code reuse. In the past, if we needed
Foo
functionality, we copy-pasted boilerplate code, but if a bug is discovered, we've lost track of everywhere it's been duplicated. - Delegate implementations can vary; we can have an implementation for a Swing Component and one for a GWT component, but their API is the same.
- Field names don't overlap, which is one of the problems with multiple inheritance.
The problems with this approach are:
- Possibly confusing. My solution is to document and hope the developer sees it.
- Method name overlapping, which is why multiple inheritance is bad (i.e., Widget may have a
getSize()
method, andIsResizeableMixin
may also declare agetSize()
). The solution is to give mixin methods distinctive names.
This is just a simple example. Putting the boolean
in the implementing class would work just as well, but I am trying to factor that out of Foo
. If we decide to change how that state is stored, all IsBusyMixin
s would need to be updated.
Any pros/cons I'm missing?
Note that Java 8's default interface implementations don't cover this use-case since mixins must hold some state.