Un concessionnaire automobile
Cette semaine, c'est Gabriel qui vous propose un #KataOfTheWeek : Car maintenance
Briefing du Kata : Dans le cadre de son activité, Bob, concessionnaire automobile doit exécuter différentes tâches:
- Effectuer des contrôles technique
- Évaluer le prix d'une voiture
Bob voudrait un programme qui puisse lui donner des informations permettant de faciliter ces deux tâches. Ayant des connaissances en informatique il a déjà créé le model qui lui paraît le plus adéquat pour répondre à ses besoins.
public interface CarElement {}
public class Car {
private final List<CarElement> carElements;
public Car(final List<CarElement> carElements) {
this.carElements = carElements;
}
public List<CarElement> getCarElements() {
return carElements;
}
}
public class Engine implements CarElement {
private final int power;
private final int weight;
private final List<CarElement> screws;
public Engine(final int power, final int weight, final List<CarElement> screws) {
this.power = power;
this.weight = weight;
this.screws = screws;
}
public int getPower() {
return power;
}
public int getWeight() {
return weight;
}
public List<CarElement> getScrews() {
return screws;
}
}
public class Screw implements CarElement {}
public class Wheel implements CarElement {}
Bob a un droit de regard sur notre travail et n'apprécie pas trop que l'on touche à ce modèle, il veut le garder isolé des actuels (prix, contrôle technique) et des possibles futurs traitements. Il a émis les exigences suivantes:
- Aucune modifications des classes existante excepté le droit d'ajouter une seule méthode à l'interface CarElement, dont l'implémentation sera identique et sans logique métier dans les classes concernées.
- interdiction d'utiliser
instanceof
, du cast, de la reflexion - utilisation du pattern carVisitor, avec deux visiteurs différents pour les deux tâches à exécuter.
Pour un véhicule donné en entrée le programme doit:
1 Calculer le prix:
Il correspond à la somme du prix de ses éléments (roues, moteur, vis), ainsi que des sous-éléments.
- roue: 200€ l'unité
- moteur: 5 * poids + 10 * puissance
- vis: 0.5€ l'unité pour les 5 premières vis, 0€ pour les suivantes
2 Lister le nombre de chaque éléments qui le compose (il peut y avoir n'importe quel nombre de roues, de moteurs etc…):
vis: 250
roue: 3
moteur: 1
Programme
public class Launcher {
public static void main(final String... args) {
final Car car = initCar();
// Compute and print the number of each elements of the car
// Compute and print the price of the car
}
// Example of car, you can modify it, add engine, screw,, wheels...
public static Car initCar() {
final Engine engine = new Engine(50,
150,
List.of(new Screw(), new Screw(), new Screw())
);
final List<CarElement> carElements = List.of(
engine,
new Wheel(),
new Screw(),
new Wheel(),
new Screw(),
new Wheel(),
new Screw(),
new Wheel());
return new Car(carElements);
}
}
Saurez-vous résoudre le problème ?
Bon courage !
Et voici une solution proposée par l'auteur en Java:
public interface CarVisitor {
void visit(final Engine engine);
void visit(final Wheel wheel);
void visit(final Screw screw);
default void visitCar(final Car car) {
for (final CarElement carElement : car.getCarElements()) {
carElement.accept(this);
}
}
}
public class PrintElementsVisitor implements CarVisitor {
private int numberOfScrews;
private int numberOfEngines;
private int numberOfWheels;
@Override
public void visit(final Engine engine) {
this.numberOfEngines++;
engine.getScrews().forEach((s) -> s.accept(this));
}
@Override
public void visit(final Wheel wheel) {
this.numberOfWheels++;
}
@Override
public void visit(final Screw screw) {
this.numberOfScrews++;
}
public void print() {
System.out.println("vis: " + numberOfScrews);
System.out.println("roue: " + numberOfWheels);
System.out.println("moteur: " + numberOfEngines);
}
}
public class ComputePriceVisitor implements CarVisitor {
private double price;
private int numberOfScrews;
@Override
public void visit(final Engine engine) {
price += (engine.getPower() * 10 + engine.getWeight() * 5);
engine.getScrews().forEach((s) -> s.accept(this));
}
@Override
public void visit(final Wheel wheel) {
price += 200;
}
@Override
public void visit(final Screw screw) {
if(numberOfScrews < 5) {
price += 0.5;
}
numberOfScrews ++;
}
public double getPrice() {
return price;
}
}
public interface CarElement {
void accept(CarVisitor carVisitor);
}
// implémentation identique dans Wheel, Engine et Screw
@Override
public void accept(final CarVisitor carVisitor) {
carVisitor.visit(this);
}
public static void main(final String... args) {
final Car car = initCar();
final PrintElementsVisitor printElementsVisitor = new PrintElementsVisitor();
printElementsVisitor.visitCar(car);
printElementsVisitor.print();
final ComputePriceVisitor computePriceVisitor = new ComputePriceVisitor();
computePriceVisitor.visitCar(car);
System.out.println("prix: " + computePriceVisitor.getPrice());
}
Votre équipe TakiVeille