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

TakiVeille

TakiVeille