I have some class inheritance SubClass < MidClass < SuperClass and want to perform some TASK upward for all these classes. TASK is quite complex with only minor changes in the 3 classes, which I moved into the private methods m2().
My current solution is very boiler plate:
class SuperClass {
protected void m1() {
//TASK (calls m2())
}
private void m2() {
//...
}
}
class MidClass extends SuperClass {
protected void m1() {
//same TASK (calls m2())
super.m1();
}
private void m2() {
//...
}
}
class SubClass extends MidClass {
protected void m1() {
//same TASK (calls m2())
super.m1();
}
private void m2() {
//...
}
}
Can I exploit some code reuse mechanism instead of copying TASK?
Something like the following, with m1() only in SuperClass, does not work:
class SuperClass {
protected final void m1() {
//TASK (calls m2())
if (!(this.getClass().equals(SuperClass.class))) {
super.m1();
}
}
because super.m1() does not refer to execution of the same inherited method in the context of a super class, but to the overridden method implementation. Since m1() does not exist in Object, I additionally get a compiler error...
Putting TASK in a protected final helper() method in SuperClass and calling helper() instead of copying TASK won't work, since then always SuperClass.m2() gets called.
The only alternative I can think of is slow, complicated and unsafe: using a type token as parameter, i.e. protected final void m1(Class<? extends SuperClass> clazz)
in SuperClass, and fulfilling TASK via reflection (requires to make m2() public static or use setAccessible(true) on m2()).
Do you know some better solution? AOP? Maybe some framework where you can inject a method into classes (as in C#)? Or am I missing something???
Solution for my concrete example of mixed-type equals() with default value constraints instead of ignoring the subclass value fields. Instead of Angelika Langer's solution (see http://www.angelikalanger.com/Articles/JavaSolutions/SecretsOfEquals/Equals-2.html) with private methods _compareFields() and a protected method _navigateClassHierarchy() that has to be copied into each subclass, only a protected method compareOwnFields() is used, which has to be overridden correctly in each subclass.
class SuperClass {
// ...
@Override
public final boolean equals(final Object other) {
if (other == this) { return true; }
if (!(other instanceof SuperClass)) {
return false;
}
final SuperClass otherSuperClass = (SuperClass) other;
return compareOwnFields(otherSuperClass, false)
&& otherSuperClass.compareOwnFields(this, true);
}
protected boolean compareOwnFields(final SuperClass other,
final boolean firstTraversal) {
if (!firstTraversal) {
return true;
}
if (field1 != other.getField1()) {
return false;
}
// compare other fields similarly ...
return true;
}
}
class SubClass {
// ...
@Override
protected boolean compareOwnFields(final SuperClass other,
final boolean firstTraversal) {
if (other instanceof SubClass && !firstTraversal) {
return true;
if (other instanceof SubClass) {
if (field1 != ((SubClass) other).getField1()) {
return false;
}
// compare other fields similarly ...
return super.compareOwnFields(other, firstTraversal);
} else {
if (field1 != DEFAULT_FIELD1) {
return false;
}
// check other fields for default values similarly ..
return super.compareOwnFields(other, firstTraversal);
}
}
}
But this does not answer my question in general, it's rather a redesign that avoids the problem. So further answers on how to solve the problem with the Java language features are very welcome!