Délégation vs abstraction
Pour cet exercice, vous pouvez démarrer un nouveau projet java standard, ou utilisez celui-ci comme base.
Afin de bien faire comprendre la différence entre Delegate
et Interface
,
nous utiliserons l'implémentation suivante d'une classe Animal
.
public class Animal {
public void move() {
System.out.println("je marche à quatre pattes.");
}
public void eat() {
System.out.println("je mange de la viande.");
}
}
public class Lion
extends Animal {}
Cette classe peut sembler assez générique si les animaux supportés par notre application se limitent aux lions, guépards, hyènes tachetées, chacals et léopards.
Qu'arrive-t-il si nous devons désormais supporter le pygargue vocifère qui est un oiseau qui vole et qui ne mange que du poisson ?
Nous pouvons commencer par extraire des interfaces Eater
et Mover
que notre classe Animal
implémentera.
public interface Mover {
void move();
}
public interface Eater {
void eat();
}
public class Animal
implements Mover, Eater {
@Override
public void move() {
System.out.println("je marche à quatre pattes.");
}
@Override
public void eat() {
System.out.println("je mange de la viande.");
}
}
Maintenant, nous pourrons extraire deux délégations (MeatEater
et FourLegsMover
) qui seront passées en argument
au constructeur de la classe Animal
.
public interface Mover {
void move();
}
public class FourLegsMover
implements Mover {
@Override
public void move() {
System.out.println("je marche à quatre pattes.");
}
}
public interface Eater {
void eat();
}
public class MeatEater
implements Eater {
@Override
public void eat() {
System.out.println("je mange de la viande.");
}
}
public class Animal
implements Mover, Eater {
private final Mover mover;
private final Eater eater;
public Animal(Mover mover, Eater eater) {
this.mover = mover;
this.eater = eater;
}
@Override
public void move() {
mover.move();
}
@Override
public void eat() {
eater.eat();
}
}
Désormais, nous avons beaucoup plus de flexibilité pour supporter plusieurs aux animaux avec des habitudes alimentaires et des modes de déplacement distincts.
À titre d'exemple, voici les implémentations concrètes de la classe Lion
et PygargueVocifere
représentées sous forme
de sous-classe de la classe Animal
:
public class Lion
extends Animal {
public Lion() {
super(new FourLegsMover(), new MeatEater());
}
}
public class FlyMover
implements Mover {
@Override
public void move() {
System.out.println("je vole avec mes ailes.");
}
}
public class FishEater
implements Eater {
@Override
public void eat() {
System.out.println("je mange du poisson.");
}
}
public class PygargueVocifere
extends Animal {
public PygargueVocifere() {
super(new FlyMover(), new FishEater());
}
}
Finalement, voici une représentation UML du design que nous venons de créer.
Solution
Vous pouvez trouvez une solution potentielle dans la branche solution
du dépôt github fourni ci-haut.