jeudi 26 novembre 2020

Java Interface does not take into consdieration method implementation from the super class

The following example with ducks, is based on the Head First design patterns book.

I have a game with different types of ducks. There is a super class Duck and it has two behaviours: fly and quack, which are stored in fields. The concrete classes decide (in the constructor) which behaviour a concrete breed has (see MalardDuck class).

I realised I want my ducks to not only have type Duck but also Quackable (so that I can have methods that accept only quackables - assuming that there are other types that quack - see Lake class). When I implement the interface in MallardDuck, the compiler complains that the class does not have the method quack although it is defined in its superclass - Duck class.

Now I could think of two solutions:

  1. Overwrite a method quack by just calling the method from the superclass: super.quack() <- but that seems unnecessary (in theory) - a child class has a direct access to superclass's public methods, so why the interface Quackable even complains...?
  2. Make Duck implement the Quackable -> this is rather illogical cause some Ducks don't Quack (their quackBehaviour is implemented with SiletnQuack class).

However in both solutions the duck:

  • HAS A quackable behaviour, AND
  • IS A quackable

Isn't that fundamentally wrong? What am I missing?

abstract class Duck{
    protected Flyiable flyBehaviour;
    protected Quackable quackBehaviour;
    public void quack(){
        quackBehaviour.quack();
    }
    void performFly(){
        flyBehaviour.fly();
    }
    void swim(){
        // swimming implementation
    }
    abstract void display();
}
interface Quackable{
    void quack();
}
class Quack implements Quackable{

    @Override
    public void quack() {
        System.out.println("Quack!");
    }
}
class Quack implements Quackable{

    @Override
    public void quack() {
        System.out.println("Quack!");
    }
}
class SilentQuack implements Quackable{

    @Override
    public void quack() {
        System.out.println("...");
    }
}
class MallardDuck extends Duck{
    public MallardDuck(){
        quackBehaviour = new Quack();
        flyBehaviour = new FlyWithWings();
    }

    @Override
    void display() {

        // it looks like a Mallard duck
    }
}

What if I want to accept ducks to this method as quackables (along with other animals):


class Lake{
    ArrayList<Quackable> quackingAnimals;
    void addQuackingAnimal(Quackable animal){
        quackingAnimals.add(animal);
    }
    void displayQuackables(){
        //...
    }
}

Solution 1:

class MallardDuck extends Duck implements Quackable {
    public MallardDuck(){
        quackBehaviour = new Quack();
        flyBehaviour = new FlyWithWings();
    }

    @Override
    void display() {

        // it looks like a Mallard duck
    }

    @Override
    public void quack() {
        super.quack();
    }
}

Solution 2:

abstract class Duck implements Quackable{
    protected Flyiable flyBehaviour;
    protected Quackable quackBehaviour;
    public void quack(){
        quackBehaviour.quack();
    }
    void performFly(){
        flyBehaviour.fly();
    }
    void swim(){
        // swimming implementation
    }
    abstract void display();
}

Aucun commentaire:

Enregistrer un commentaire