return new StringBuffer().append("Now is ").append(new Date()).append(", and ticking...").toString();
and be able to subclass at the same time.
See, the problem is that if you setter returns
this
:MyBaseEntity withExcitingNewFeature(ExcitingNewFeature f) { features.add(f); return this; }
and then you subclass
MyBaseEntity
, like MyDerivedEntity extends MyBaseClass
, you won't be able to writeMyDerivedEntity mde = new MyDerivedEntity(entityId).withExcitingNewFeature(feature);
Since, well, the class is different.
So in my previous post I suggested to make
MyBaseEntity
type-dependent (that is, have a generic): public abstract class MyBaseEntity<T extends MyBaseEntity>
and declare a method
abstract T self();
So that every subclass declaration would look like this:
public class MyDerivedEntity extends MyBaseEntity<MyDerivedEntity>
and would define
MyDerivedEntity self() { return this; }
Yes, it works. And probably for 2008, with is now ancient history, when slow people slowly typed their slow code, not caring about the speed of development... in short, it was long ago.
Now there's a better solution. No need to redefine self() in all possible subclasses. That was just stupid. The only place where it should be defined is the base class:
T self() { return (T) this; }
And no need to declare MyBaseEntity abstract.
There's also a bug in that old post; the generic type should have been bounded, as Ran noted in his comment.
Of course all setters should look like this:
<T extends MyBaseEntity> T withExcitingNewFeature(ExcitingNewFeature f) { features.add(f); return self(); }
2 comments:
You have a problem in this design. Try inheriting from MyDerivedEntity - let's call it MyDerivedDerivedEntity. What type is self()?
Should not declaration "MyBaseEntity withExcitingNewFeature(ExcitingNewFeature f)" be "T withExcitingNewFeature(ExcitingNewFeature f)"?
Post a Comment