0

So I have a class that looks something like this:

public abstract class GameObject {

    public abstract boolean hasValidLocation();

    //some more code that will use hasValidLocation
}

and an interface:

public interface Collidable {

    //some abstract references to functions of the game object

    default boolean hasValidLocation() {
        //checks whether or not the the game object has  a valid locaton
    }
}

and I have a similar interface for NotCollidable and would like to implement the abstract function hasValidLocation from the game object with this interface:

public class GameObject1 extends GameObject implements Collidable {
    //some code
}

but java says that GameObject1 does not implement hasValidLocation. I can't use 2 abstract classes since I already split gameObject in a DynamicGameObject and StaticGameObject and those can both be collidable and not collidable.

Is there something I did wrong or an alternative solution that doesn't require me to write hasValidLocation() multiple times?

coder
  • 8,346
  • 16
  • 39
  • 53
nomis6432
  • 236
  • 2
  • 10
  • It's supposed to be `public abstract boolean hasValidLocation()` I didn't copy it properly. – nomis6432 May 06 '18 at 10:19
  • 1
    Possible duplicate of [Default interface method for abstract superclass](https://stackoverflow.com/questions/43943553/default-interface-method-for-abstract-superclass) – Bogdan Lukiyanchuk May 06 '18 at 10:34

4 Answers4

2

I missed part of the question.

Perhaps your base abstract class should implement a super-interface common to Collidable and NotCollidable:

For example:

interface LocationValidatable {
    default boolean hasValidLocation() {
      return false;
    }
}

interface Collidable extends LocationValidatable {
    default boolean hasValidLocation() {
      return true; // replace with actual logic
    }
}

interface NotCollidable extends LocationValidatable {
    default boolean hasValidLocation() {
      return false; // replace with actual logic
    }
}

abstract class GameObject implements LocationValidatable {
    //some more code that will use hasValidLocation
}

Now, each concrete sub-class can choose whether to implement Collidable or NotCollidable:

class GameObject1 extends GameObject implements Collidable {
    //some code
}

class GameObject2 extends GameObject implements NotCollidable {
    //some code
}
Eran
  • 387,369
  • 54
  • 702
  • 768
  • The child classes of GameObject can be Collidable or NotCollidable so I'm not sure if that would work. Do you mean that I'd implement Collidable on GameObject and when I want to make a GameObject NotCollidable that I'd have to overwrite it by implementing NotCollidable on it? – nomis6432 May 06 '18 at 10:16
1

Why not do something entirely different? Whenever you use the hasValidLocation method you can just check if the GameObject actually implements the Collidable interface.

Here is the code for the GameObject class:

public class GameObject
{
    // The GameObject actually does not contain a hasValidLocation() method.
}

And here is the code for the Collidable interface.

public interface Collidable
{
     // The Collidable interface actually contains the hasValidLocation() method.
     public abstract boolean hasValidLocation();
}

Here is just a quick example how you can determine if the gameObject implements the Collidable interface.

if (gameObject instanceof Collidable)
{
    final boolean isValid = ((Collidable) gameObject).hasValidLocation();
}
  • Thank you for your suggestion. While this would work I'm not sure if this is the best way to go about it since it would be possible to create GameObjects that would mean I'd be able to create GameObjects that don't implement Collidable or NotCollidable which could give some problems. I think I'm going to go with what @Diasiare suggested. – nomis6432 May 06 '18 at 10:34
  • Why not treat classes who don't implement the `Collidable` interface as classes that implement the `NotCollidable` interface? –  May 06 '18 at 10:52
1

default methods are not abstract thus you need not to override it.

Thus you just need to override the abstract method in GameObject class.

So when you override like this

@Override
   public boolean hasValidLocation()
   {
      // TODO Auto-generated method stub
      return false;
   }

this is overriding method in GameObject interface

Shubhendu Pramanik
  • 2,711
  • 2
  • 13
  • 23
  • Thank you but the problem with overriding it in the GameObject class is that I'd have to write the same code multiple times since different GameObjects can be collidable and not collidable. I think I'm going to go with what @Diasiare suggested. – nomis6432 May 06 '18 at 10:32
  • 1
    @nomis6432 In practical scenario Duplicate default methods are not allowed in same class implementing the interfaces unless you override it. Secondly in production environment changing method name is not recommended. Eran's approach is better – Shubhendu Pramanik May 06 '18 at 10:39
1

You can solve this problem simply by changing the name of one of the hasValidLocation methods.

For example

public interface Collidable {


    default boolean calculateLocationValidity() {
        return true;    
    }

}

and:

public class GameObject1 extends GameObject implements Collidable {

    public boolean hasValidLocation() {
        return calculateLocationValidity();
    }
}
Diasiare
  • 745
  • 1
  • 6
  • 18
  • Thank you for your solution. I think I'm going to go with this. It is not perfect since I'll have to write `public boolean hasValidLocation(){return calculateLocationValidity();}` but it looks the best in my opinion. – nomis6432 May 06 '18 at 10:36
  • the solution from @Eran is a bit more elegant so I'm going to go with that one instead thanks anyway for your suggestion. – nomis6432 May 06 '18 at 10:45