Re: Function that returns derived class?
aaronfude@gmail.com wrote:
Can the overriding and the casts be avoided with some kind of template
structure?
As Ben already explained, there are no "template structures" in Java.
Assuming a "kind of ..." means Java generics, just another simple
approach in your case might be:
public class A<T extends A> {
public T cool() {
System.out.println("Hello, World");
return (T)this; // unsafe!
}
}
public class B extends A<B> {
public void anotherFunction() { }
}
It allows for usage like that:
new A().cool(); // raw type A is used here!
new B().cool().anotherFunction();
However, mixing a raw and parameterized types is discouraged, and usage
of it is limited to a single level of inheritance only (erasure of B
declared as "class B<T extends B<T>> extends A<T>", without overriding a
cool() method, results in A (not B) taken as a return type for that method).
Safer approach is to have a generic base class for A and B:
public abstract class Base<T extends Base<T>> {
protected abstract T getT();
public T cool() {
System.out.println("Hello, World");
return getT();
}
}
public class A extends Base<A> {
protected A getT() { return this; }
}
public class B extends Base<B> {
protected B getT() { return this; }
public void anotherFunction() { }
}
There is no problem now in using A and B the way you expect (there is
also easy way to extend that "pattern" with other classes, e.g.
introducing another generic base class for B derived from the A's base
class). Unfortunately, it disallows a direct inheritance of A from B,
so then B can not be used as replacement of A anymore. Partial solution
for that problem may appear already mentioned extended version of that
"pattern", i.e.:
public abstract class ABase<T extends ABase<T>> {
protected abstract T getT();
public T cool() {
System.out.println("Hello, World");
return getT();
}
}
public abstract class BBase<T extends BBase<T>> extends ABase<T> {
public void anotherFunction() { }
}
public class A extends ABase<A> {
protected A getT() { return this; }
}
public class B extends BBase<B> {
protected B getT() { return this; }
}
There's still illegal to do that:
A a = new A();
B b = new B();
a = b;
But the following is legal now:
ABase<?> a = new A();
BBase<?> b = new B();
a = b;
(Using A and B as a names for the abstract base classes, and e.g. AImpl
and BImpl for a concrete implementations' names appears more convenient
for me in that extended "pattern". Consider that if you'll decide to
use it.)
piotr