Menu
Coddy logo textTech

Service de location de véhicules

Fait partie de la section Programmation Orientée Objet du Journey Java de Coddy — leçon 87 sur 87.

Pour ce défi final, vous allez construire un système de Service de Location de Véhicules qui regroupe tous les concepts de la POO que vous avez maîtrisés tout au long de ce cours.

Votre système doit modéliser une flotte de différents types de véhicules. Considérez une classe de base Vehicle avec des propriétés communes telles que la plaque d'immatriculation, la marque et le tarif de location journalier. Des sous-classes telles que Car, Motorcycle et Truck peuvent étendre cela avec des attributs spécifiques comme le nombre de sièges, la cylindrée du moteur ou la capacité de chargement.

Les interfaces peuvent définir des comportements de location : une interface Rentable pourrait déclarer des méthodes comme rent(), returnVehicle() et calculateCost(int days). Différents types de véhicules pourraient implémenter des stratégies de tarification différemment, ce qui en fait un cas d'utilisation parfait pour le polymorphisme.

Réfléchissez à la manière dont une classe RentalAgency gère la flotte en utilisant la composition.

Les exceptions personnalisées comme VehicleNotAvailableException peuvent gérer les cas particuliers.

Vous pourriez appliquer le pattern Factory pour créer des véhicules ou utiliser des enums pour les catégories de véhicules et le statut de location.

Ce défi teste votre capacité à concevoir un système POO complet et bien structuré. Bonne chance !

challenge icon

Défi

Facile

Construisons un service complet de location de véhicules qui rassemble tout ce que vous avez appris sur la POO ! Vous allez créer un système qui gère une flotte de différents types de véhicules, gère les locations avec une validation appropriée et utilise un modèle de fabrique pour créer des véhicules.

Vous organiserez votre code sur sept fichiers :

  • RentalStatus.java : Créez un enum représentant le statut de location d'un véhicule. Incluez les valeurs AVAILABLE, RENTED et MAINTENANCE. Ajoutez un champ privé description (String), un constructeur et un getter. AVAILABLE doit avoir la description "ready to rent", RENTED doit avoir "currently in use" et MAINTENANCE doit avoir "under service".
  • VehicleNotAvailableException.java : Créez une exception personnalisée qui étend Exception. Le constructeur doit accepter une plaque d'immatriculation et créer un message au format Vehicle not available: [licensePlate].
  • Rentable.java : Créez une interface définissant les opérations de location. Déclarez les méthodes rent() retournant un boolean, returnVehicle() retournant un boolean et calculateCost(int days) retournant un double.
  • Vehicle.java : Créez une classe de base abstraite pour tous les véhicules. Incluez des champs privés pour licensePlate (String), brand (String), dailyRate (double) et status (RentalStatus, initialisé à AVAILABLE). Le constructeur prend licensePlate, brand et dailyRate. Incluez les getters appropriés et un setter pour status. Déclarez une méthode abstraite getVehicleType() retournant une String. Implémentez une méthode getDetails() qui retourne "[licensePlate] [brand] ([vehicleType]) - $[dailyRate]/day - [status description]" avec dailyRate formaté à 2 décimales.
  • Car.java : Créez une classe étendant Vehicle et implémentant Rentable. Ajoutez un champ privé seats (int). Le constructeur prend licensePlate, brand, dailyRate et seats. Implémentez getVehicleType() pour retourner "Car". Pour rent(), si le statut est AVAILABLE, réglez-le sur RENTED et retournez true ; sinon retournez false. Pour returnVehicle(), si le statut est RENTED, réglez-le sur AVAILABLE et retournez true ; sinon retournez false. Pour calculateCost(int days), retournez dailyRate multiplié par days.
  • Motorcycle.java : Créez une classe étendant Vehicle et implémentant Rentable. Ajoutez un champ privé engineCC (int). Le constructeur prend licensePlate, brand, dailyRate et engineCC. Implémentez getVehicleType() pour retourner "Motorcycle". Implémentez les méthodes de Rentable de la même manière que pour Car, mais calculateCost() doit appliquer une remise de 10 % (multiplier par 0.9).
  • RentalAgency.java : Créez une classe qui gère la flotte de véhicules à l'aide d'une ArrayList. Incluez les méthodes :
    • addVehicle(Vehicle vehicle) - ajoute un véhicule à la flotte
    • findVehicle(String licensePlate) - retourne le Vehicle ou null
    • rentVehicle(String licensePlate, int days) - trouve le véhicule, tente de le louer (en le castant en Rentable) et retourne le coût de la location. Lancez VehicleNotAvailableException si le véhicule n'est pas trouvé ou si rent() retourne false
    • returnVehicle(String licensePlate) - trouve et retourne le véhicule, retournant true en cas de succès
    • getAvailableVehicles() - retourne une ArrayList de véhicules ayant le statut AVAILABLE
  • Main.java : Construisez votre service de location ! Vous recevrez une chaîne de commandes séparées par des virgules :
    • ADD_CAR:licensePlate:brand:dailyRate:seats
    • ADD_MOTORCYCLE:licensePlate:brand:dailyRate:engineCC
    • RENT:licensePlate:days
    • RETURN:licensePlate
    • AVAILABLE

    Traitez chaque commande et affichez :

    • ADD_CAR/ADD_MOTORCYCLE : Added: [brand] ([vehicleType])
    • RENT : Rented [licensePlate] for [days] days - Total: $[cost] (coût à 2 décimales), ou Error: [exception message]
    • RETURN : Returned: [licensePlate] ou Return failed: [licensePlate]
    • AVAILABLE : Affichez Available vehicles: suivi des détails de chaque véhicule disponible sur des lignes séparées

    Après toutes les commandes, affichez --- Fleet Summary --- suivi des détails de chaque véhicule.

Vous recevrez une seule entrée : la chaîne de commande séparée par des virgules.

Par exemple, avec l'entrée ADD_CAR:ABC-123:Toyota:50.00:5,ADD_MOTORCYCLE:XYZ-789:Honda:40.00:600,RENT:ABC-123:3,RENT:ABC-123:2,AVAILABLE,RETURN:ABC-123, votre sortie serait :

Added: Toyota (Car)
Added: Honda (Motorcycle)
Rented ABC-123 for 3 days - Total: $150.00
Error: Vehicle not available: ABC-123
Available vehicles:
XYZ-789 Honda (Motorcycle) - $40.00/day - ready to rent
Returned: ABC-123
--- Fleet Summary ---
ABC-123 Toyota (Car) - $50.00/day - ready to rent
XYZ-789 Honda (Motorcycle) - $40.00/day - ready to rent

Ce défi combine l'héritage (hiérarchie Vehicle), les interfaces (Rentable), les enums (RentalStatus), les exceptions personnalisées, le polymorphisme (traiter uniformément différents types de véhicules) et la composition (RentalAgency gérant les véhicules) dans un système complet de service de location !

Aide-mémoire

Ce défi final combine plusieurs concepts de la POO dans un système complet. Voici les principaux modèles et techniques :

Énumérations avec des champs

Les énumérations peuvent avoir des champs, des constructeurs et des méthodes :

public enum RentalStatus {
    AVAILABLE("ready to rent"),
    RENTED("currently in use");
    
    private String description;
    
    private RentalStatus(String description) {
        this.description = description;
    }
    
    public String getDescription() {
        return description;
    }
}

Exceptions personnalisées

Créez des exceptions spécifiques au domaine en étendant Exception :

public class VehicleNotAvailableException extends Exception {
    public VehicleNotAvailableException(String licensePlate) {
        super("Vehicle not available: " + licensePlate);
    }
}

Classes de base abstraites avec interfaces

Combinez des classes abstraites pour une implémentation partagée avec des interfaces pour les contrats de comportement :

public abstract class Vehicle {
    private String licensePlate;
    private RentalStatus status;
    
    public abstract String getVehicleType();
    
    public String getDetails() {
        return licensePlate + " " + getVehicleType() + " - " + status.getDescription();
    }
}

public interface Rentable {
    boolean rent();
    boolean returnVehicle();
    double calculateCost(int days);
}

public class Car extends Vehicle implements Rentable {
    public boolean rent() {
        if (getStatus() == RentalStatus.AVAILABLE) {
            setStatus(RentalStatus.RENTED);
            return true;
        }
        return false;
    }
}

Composition pour la gestion

Utilisez la composition pour gérer des collections d'objets :

public class RentalAgency {
    private ArrayList<Vehicle> fleet = new ArrayList<>();
    
    public void addVehicle(Vehicle vehicle) {
        fleet.add(vehicle);
    }
    
    public double rentVehicle(String licensePlate, int days) throws VehicleNotAvailableException {
        Vehicle vehicle = findVehicle(licensePlate);
        if (vehicle == null) {
            throw new VehicleNotAvailableException(licensePlate);
        }
        Rentable rentable = (Rentable) vehicle;
        if (!rentable.rent()) {
            throw new VehicleNotAvailableException(licensePlate);
        }
        return rentable.calculateCost(days);
    }
}

Le polymorphisme en action

Différentes sous-classes peuvent implémenter les méthodes d'interface différemment :

// Car : tarification standard
public double calculateCost(int days) {
    return dailyRate * days;
}

// Motorcycle : tarification avec remise
public double calculateCost(int days) {
    return dailyRate * days * 0.9;
}

Essayez vous-même

import java.util.Scanner;
import java.util.ArrayList;

class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        String input = scanner.nextLine();
        
        // TODO: Créer une instance de RentalAgency
        
        // TODO: Diviser l'entrée par des virgules pour obtenir les commandes individuelles
        
        // TODO: Traiter chaque commande :
        // ADD_CAR:licensePlate:brand:dailyRate:seats -> afficher "Added: [brand] ([vehicleType])"
        // ADD_MOTORCYCLE:licensePlate:brand:dailyRate:engineCC -> afficher "Added: [brand] ([vehicleType])"
        // RENT:licensePlate:days -> afficher "Rented [licensePlate] for [days] days - Total: $[cost]" (2 décimales)
        //                           ou "Error: [exception message]" si une exception est levée
        // RETURN:licensePlate -> afficher "Returned: [licensePlate]" ou "Return failed: [licensePlate]"
        // AVAILABLE -> afficher "Available vehicles:" suivi des détails de chaque véhicule disponible
        
        // TODO: Après toutes les commandes, afficher "--- Fleet Summary ---"
        // suivi des détails de chaque véhicule
    }
}
quiz iconTestez-vous

Cette leçon comprend un petit quiz. Commencez la leçon pour y répondre et suivre votre progression.

Toutes les leçons de Programmation Orientée Objet