Issue
I have a design question. I have a class hierarchy:
- AbstractEntity
- NPC extends AbstractEntity implements LifeForm
- Player extends AbstractEntity implements LifeForm
There is a method #moveTo(Target target). This method exists currently in both Player and NPC.
The implemetation is the same for both classes. Only one method called (getQueuedActions()) has a different implementation.
So, in theory, the whole method can be implemented at AbstractEntity, and the concrete difference is implemented at the child class level. But the Java compiler says: getQueuedActions() needs to be implemented also at AbstractEntity. I could of course do an instace of check and implement accordinly. But I thought I ask here, for I think I have something wrong here.
Is there a way to implement the method in Java indicating that yes, this does exist at AbstractEntity but look at the concrete (sub-)class for the real implementation? In Smalltalk, you would do ^implementedBySubClass. To explain, #implementedBySubClass is a way of defining a method as abstract at one level of the class hierarchy but still support a certain protocol (or interface) while not having a real implementation.
Is there an equivalent in Java?
Solution
If you put moveTo(Target)
in AbstractEntity
that would mean all AbstractEntity
es can be moved. All of them. You can't not: That's what putting it at that level means.
If NPC can be moved, and Player can be moved, but let's say Tree (also an AbstractEntity
) cannot, then moveTo
should NOT be in AbstractEntity
at all!
Possibly you want something in between; perhaps Person extends MovableEntity
and NPC extends MovableEntity
, and MovableEntity extends AbstractEntity
. And moveTo
can go in MovableEntity
.
Whether it's MovableEntity
or AbstractEntity
that gets a moveTo(Target target)
method - you are free to specify an implementation or not (the act of saying: "All Xs have the Y method" is separate from "... and here is the code for that method". You choose: Either do the first (decree that the method must be there, but not what the code for it is), or both (decree that the method must be there, and provide an implementation, which a subclass is free to override with an alternate implementation unless you want to disable that, which you can, by marking the method with the final
keyword).
That implementation is free to use any other property of the type it is in - including properties that are of the 'The type decrees this property exists, not what it looks like' variety. This is perfectly legal java:
class MovableEntity extends AbstractEntity {
public void moveTo(Target target) {
var actions = getQueuedActions();
.... move to and do the actions ....
}
public abstract List<Action> getQueuedActions();
}
This class definition says:
- You can't instantiate me; I am abstract. My only reason for existing is to serve as common supertype for other more specific types. If nobody ever writes
class Something extends MovableEntity
, this code is completely useless. - All
MovableEntity
instances regardless of its actual type have amoveTo(Target)
method, as well as agetQueuedActions
method. A subclass can't 'remove' this. - Any types that
extends
MovableEntity must provide an implementation of thegetQueuedActions
method - failure to do so is a compiler error. Unless they are markedabstract
which is fine (in which case the requirement to have that method is passed on to any subclasses of it in turn). - Any types that
extends
MovableEntity may provide its own implementation ofmoveTo(Target)
- even if it does, an impl ofgetQueuedActions
must still be provided, that rule doesn't change. If it doesn't provide an implementation, it inherits the implementation as provided here (which ends up invokinggetQueuedActions
as part of how it works).
Possibly ^implementedBySubclass
is smalltalk-ese for marking a method as abstract
. You should in general, when asking on SO questions in the vein of "This thing in language X - is there an equivalent to that in language Y?", explain what 'this thing' actually means.
Especially for Smalltalk: Documentation is hard to find.
Answered By - rzwitserloot
Answer Checked By - Robin (JavaFixing Admin)