Menu
Coddy logo textTech

Fahrzeugvermietung

Teil des Abschnitts Objektorientierte Programmierung der Java-Journey von Coddy — Lektion 87 von 87.

Für diese abschließende Herausforderung wirst du ein Vehicle Rental Service-System bauen, das alle OOP-Konzepte zusammenführt, die du im Laufe dieses Kurses gemeistert hast.

Ihr System sollte eine Flotte verschiedener Fahrzeugtypen modellieren. Betrachten Sie eine Basisklasse Vehicle mit gemeinsamen Eigenschaften wie Kennzeichen, Marke und täglicher Mietrate. Subklassen wie Car, Motorcycle und Truck können diese um spezifische Attribute wie die Anzahl der Sitze, den Hubraum oder die Ladekapazität erweitern.

Interfaces können Mietverhalten definieren: Ein Rentable-Interface könnte Methoden wie rent(), returnVehicle() und calculateCost(int days) deklarieren. Verschiedene Fahrzeugtypen könnten Preisstrategien unterschiedlich implementieren, was dies zu einem perfekten Anwendungsfall für Polymorphismus macht.

Überlegen Sie, wie eine RentalAgency Klasse die Flotte mittels Komposition verwaltet.

Benutzerdefinierte Ausnahmen wie VehicleNotAvailableException können Sonderfälle behandeln.

Sie könnten das Factory-Pattern anwenden, um Fahrzeuge zu erstellen, oder Enums für Fahrzeugkategorien und den Mietstatus verwenden.

Diese Herausforderung testet Ihre Fähigkeit, ein vollständiges, gut strukturiertes OOP-System zu entwerfen. Viel Glück!

challenge icon

Aufgabe

Einfach

Lassen Sie uns einen vollständigen Fahrzeugvermietungsdienst aufbauen, der alles zusammenführt, was Sie über OOP gelernt haben! Sie erstellen ein System, das eine Flotte verschiedener Fahrzeugtypen verwaltet, Vermietungen mit ordnungsgemäßer Validierung abwickelt und ein Factory-Muster zur Erstellung von Fahrzeugen verwendet.

Sie werden Ihren Code über sieben Dateien organisieren:

  • RentalStatus.java: Erstellen Sie ein Enum, das den Mietstatus eines Fahrzeugs darstellt. Fügen Sie die Werte AVAILABLE, RENTED und MAINTENANCE hinzu. Fügen Sie ein privates Feld description (String), einen Konstruktor und einen Getter hinzu. Available sollte die Beschreibung "ready to rent" haben, rented sollte "currently in use" haben und maintenance sollte "under service" haben.
  • VehicleNotAvailableException.java: Erstellen Sie eine benutzerdefinierte Exception, die Exception erweitert. Der Konstruktor sollte ein Kennzeichen akzeptieren und eine Nachricht im Format Vehicle not available: [licensePlate] erstellen.
  • Rentable.java: Erstellen Sie ein Interface, das Mietoperationen definiert. Deklarieren Sie die Methoden rent(), die einen boolean zurückgibt, returnVehicle(), die einen boolean zurückgibt, und calculateCost(int days), die einen double zurückgibt.
  • Vehicle.java: Erstellen Sie eine abstrakte Basisklasse für alle Fahrzeuge. Fügen Sie private Felder für licensePlate (String), brand (String), dailyRate (double) und status (RentalStatus, initialisiert auf AVAILABLE) hinzu. Der Konstruktor nimmt licensePlate, brand und dailyRate entgegen. Fügen Sie entsprechende Getter und einen Setter für status hinzu. Deklarieren Sie eine abstrakte Methode getVehicleType(), die einen String zurückgibt. Implementieren Sie eine getDetails()-Methode, die "[licensePlate] [brand] ([vehicleType]) - $[dailyRate]/day - [status description]" zurückgibt, wobei dailyRate auf 2 Dezimalstellen formatiert ist.
  • Car.java: Erstellen Sie eine Klasse, die Vehicle erweitert und Rentable implementiert. Fügen Sie ein privates Feld seats (int) hinzu. Der Konstruktor nimmt licensePlate, brand, dailyRate und seats entgegen. Implementieren Sie getVehicleType() so, dass "Car" zurückgegeben wird. Für rent(): Wenn der Status AVAILABLE ist, setzen Sie ihn auf RENTED und geben Sie true zurück; andernfalls geben Sie false zurück. Für returnVehicle(): Wenn der Status RENTED ist, setzen Sie ihn auf AVAILABLE und geben Sie true zurück; andernfalls geben Sie false zurück. Für calculateCost(int days) geben Sie dailyRate multipliziert mit days zurück.
  • Motorcycle.java: Erstellen Sie eine Klasse, die Vehicle erweitert und Rentable implementiert. Fügen Sie ein privates Feld engineCC (int) hinzu. Der Konstruktor nimmt licensePlate, brand, dailyRate und engineCC entgegen. Implementieren Sie getVehicleType() so, dass "Motorcycle" zurückgegeben wird. Implementieren Sie die Rentable-Methoden auf die gleiche Weise wie bei Car, aber calculateCost() sollte einen Rabatt von 10 % anwenden (mit 0.9 multiplizieren).
  • RentalAgency.java: Erstellen Sie eine Klasse, die die Fahrzeugflotte mithilfe einer ArrayList verwaltet. Fügen Sie folgende Methoden hinzu:
    • addVehicle(Vehicle vehicle) - fügt ein Fahrzeug zur Flotte hinzu
    • findVehicle(String licensePlate) - gibt das Vehicle oder null zurück
    • rentVehicle(String licensePlate, int days) - findet das Fahrzeug, versucht es zu mieten (Casting zu Rentable) und gibt die Mietkosten zurück. Werfen Sie eine VehicleNotAvailableException, wenn das Fahrzeug nicht gefunden wird oder wenn rent() false zurückgibt
    • returnVehicle(String licensePlate) - findet und gibt das Fahrzeug zurück, gibt true bei Erfolg zurück
    • getAvailableVehicles() - gibt eine ArrayList von Fahrzeugen mit dem Status AVAILABLE zurück
  • Main.java: Bauen Sie Ihren Vermietungsdienst! Sie erhalten einen kommagetrennten String mit Befehlen:
    • ADD_CAR:licensePlate:brand:dailyRate:seats
    • ADD_MOTORCYCLE:licensePlate:brand:dailyRate:engineCC
    • RENT:licensePlate:days
    • RETURN:licensePlate
    • AVAILABLE

    Verarbeiten Sie jeden Befehl und geben Sie Folgendes aus:

    • ADD_CAR/ADD_MOTORCYCLE: Added: [brand] ([vehicleType])
    • RENT: Rented [licensePlate] for [days] days - Total: $[cost] (Kosten auf 2 Dezimalstellen), oder Error: [exception message]
    • RETURN: Returned: [licensePlate] oder Return failed: [licensePlate]
    • AVAILABLE: Geben Sie Available vehicles: aus, gefolgt von den Details jedes verfügbaren Fahrzeugs in separaten Zeilen

    Geben Sie nach allen Befehlen --- Fleet Summary --- aus, gefolgt von den Details jedes Fahrzeugs.

Sie erhalten eine Eingabe: den kommagetrennten Befehls-String.

Zum Beispiel bei der Eingabe 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 wäre Ihre Ausgabe:

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

Diese Herausforderung kombiniert Vererbung (Vehicle-Hierarchie), Interfaces (Rentable), Enums (RentalStatus), benutzerdefinierte Exceptions, Polymorphismus (einheitliche Behandlung verschiedener Fahrzeugtypen) und Komposition (RentalAgency verwaltet Fahrzeuge) zu einem vollständigen Vermietungssystem!

Spickzettel

Diese abschließende Herausforderung kombiniert mehrere OOP-Konzepte zu einem vollständigen System. Hier sind die wichtigsten Muster und Techniken:

Enums mit Feldern

Enums können Felder, Konstruktoren und Methoden haben:

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;
    }
}

Benutzerdefinierte Exceptions

Erstellen Sie domänenspezifische Exceptions, indem Sie Exception erweitern:

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

Abstrakte Basisklassen mit Interfaces

Kombinieren Sie abstrakte Klassen für die gemeinsame Implementierung mit Interfaces für Verhaltensverträge:

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;
    }
}

Komposition zur Verwaltung

Verwenden Sie Komposition, um Sammlungen von Objekten zu verwalten:

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);
    }
}

Polymorphismus in Aktion

Verschiedene Unterklassen können Interface-Methoden unterschiedlich implementieren:

// Auto: Standardpreisgestaltung
public double calculateCost(int days) {
    return dailyRate * days;
}

// Motorrad: ermäßigte Preisgestaltung
public double calculateCost(int days) {
    return dailyRate * days * 0.9;
}

Probier es selbst

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: Erstelle eine RentalAgency-Instanz
        
        // TODO: Trenne die Eingabe durch Kommas, um einzelne Befehle zu erhalten
        
        // TODO: Verarbeite jeden Befehl:
        // ADD_CAR:licensePlate:brand:dailyRate:seats -> gib "Added: [brand] ([vehicleType])" aus
        // ADD_MOTORCYCLE:licensePlate:brand:dailyRate:engineCC -> gib "Added: [brand] ([vehicleType])" aus
        // RENT:licensePlate:days -> gib "Rented [licensePlate] for [days] days - Total: $[cost]" aus (2 Dezimalstellen)
        //                           oder "Error: [exception message]", falls eine Exception geworfen wird
        // RETURN:licensePlate -> gib "Returned: [licensePlate]" oder "Return failed: [licensePlate]" aus
        // AVAILABLE -> gib "Available vehicles:" aus, gefolgt von den Details jedes verfügbaren Fahrzeugs
        
        // TODO: Gib nach allen Befehlen "--- Fleet Summary ---" aus
        // gefolgt von den Details jedes Fahrzeugs
    }
}
quiz iconTeste dich selbst

Diese Lektion enthält ein kurzes Quiz. Starte die Lektion, um es zu beantworten und deinen Fortschritt zu speichern.

Alle Lektionen in Objektorientierte Programmierung