Search code examples
javaoopsmalltalk

Is there an equivalent to #implementedBySubclass in Java?


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 AbstractEntityes 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 a moveTo(Target) method, as well as a getQueuedActions method. A subclass can't 'remove' this.
    • Any types that extends MovableEntity must provide an implementation of the getQueuedActions method - failure to do so is a compiler error. Unless they are marked abstract 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 of moveTo(Target) - even if it does, an impl of getQueuedActions 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 invoking getQueuedActions 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.