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:
- 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...?
- 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