Menu
Coddy logo textTech

Fahrzeugvermietung

Teil des Abschnitts Objektorientierte Programmierung der PHP-Journey von Coddy — Lektion 91 von 91.

challenge icon

Aufgabe

Einfach

Lassen Sie uns ein Vehicle Rental Service System bauen, das eine Fahrzeugflotte verwaltet, Kundenvermietungen verfolgt und die Preise basierend auf dem Fahrzeugtyp berechnet. Diese umfassende Herausforderung vereint Vererbung, Interfaces, Kapselung und das State-Pattern, um eine realistische Anwendung für ein Vermietungsunternehmen zu erstellen.

Sie werden Ihren Code über sieben Dateien organisieren:

  • VehicleState.php — Definieren Sie ein VehicleState Interface, das die verschiedenen Zustände darstellt, in denen sich ein Fahrzeug befinden kann. Fügen Sie zwei Methoden hinzu: getStatus(): string und canRent(): bool. Erstellen Sie dann drei Klassen, die dieses Interface implementieren:
    • AvailableState — gibt "Available" und true zurück
    • RentedState — gibt "Rented" und false zurück
    • MaintenanceState — gibt "Maintenance" und false zurück
  • Vehicle.php — Binden Sie die VehicleState-Datei ein. Erstellen Sie eine abstrakte Klasse Vehicle mit Constructor Promotion für licensePlate (string, public readonly), brand (string, public readonly) und dailyRate (float, protected). Speichern Sie den aktuellen Zustand in einer privaten Eigenschaft, standardmäßig AvailableState. Implementieren Sie:
    • getState(): VehicleState — gibt den aktuellen Zustand zurück
    • setState(VehicleState $state): void — ändert den Zustand
    • getStatus(): string — delegiert an getStatus() des Zustands
    • canRent(): bool — delegiert an canRent() des Zustands
    • abstract calculateCost(int $days): float — jeder Fahrzeugtyp berechnet die Kosten unterschiedlich
    • getType(): string — gibt den Klassennamen mittels static::class zurück
  • Vehicles.php — Binden Sie die Vehicle-Datei ein. Erstellen Sie drei konkrete Fahrzeugklassen:
    • Car — erweitert Vehicle; calculateCost() gibt dailyRate * days zurück
    • Motorcycle — erweitert Vehicle; calculateCost() gibt dailyRate * days * 0.8 zurück (20% Rabatt)
    • Van — erweitert Vehicle mit einem zusätzlichen Parameter $mileageRate (float); calculateCost(int $days, int $miles = 0) gibt (dailyRate * days) + (mileageRate * miles) zurück
  • Customer.php — Erstellen Sie eine Klasse Customer mit Constructor Promotion für id (int, public readonly) und name (string, public readonly). Verfolgen Sie die Miethistorie in einem privaten Array. Implementieren Sie:
    • addRental(string $vehiclePlate, float $cost): void — fügt einen Eintrag zur Historie hinzu
    • getRentalCount(): int — gibt die Anzahl der Vermietungen zurück
    • getTotalSpent(): float — gibt die Summe aller Mietkosten zurück
  • Rental.php — Binden Sie die Vehicle- und Customer-Dateien ein. Erstellen Sie eine Klasse Rental, die einen Kunden mit einem Fahrzeug verknüpft. Nutzen Sie Constructor Promotion für customer (Customer, public readonly), vehicle (Vehicle, public readonly), days (int, private) und optional miles (int, private, Standard 0). Implementieren Sie:
    • calculateTotal(): float — wenn das Fahrzeug ein Van ist, übergeben Sie miles an calculateCost(); andernfalls übergeben Sie nur days
    • complete(): string — berechnet die Gesamtsumme, fügt sie der Historie des Kunden hinzu, setzt das Fahrzeug auf AvailableState und gibt "Rental completed: $[total]" zurück (2 Dezimalstellen)
  • RentalService.php — Binden Sie die Rental- und Vehicles-Dateien ein. Erstellen Sie eine Klasse RentalService, die die Flotte verwaltet. Speichern Sie Fahrzeuge in einem privaten Array, indiziert nach dem Kennzeichen (license plate). Implementieren Sie:
    • addVehicle(Vehicle $vehicle): void — fügt ein Fahrzeug zur Flotte hinzu
    • findVehicle(string $plate): ?Vehicle — gibt das Fahrzeug oder null zurück
    • getAvailableVehicles(): array — gibt Fahrzeuge zurück, bei denen canRent() wahr ist
    • rentVehicle(Customer $customer, string $plate, int $days, int $miles = 0): string|Rental — wenn das Fahrzeug nicht gefunden wird, geben Sie "Vehicle not found" zurück; wenn es nicht verfügbar ist, geben Sie "Vehicle is not available" zurück; andernfalls setzen Sie das Fahrzeug auf RentedState und geben ein neues Rental-Objekt zurück
    • setMaintenance(string $plate): string — setzt das Fahrzeug auf MaintenanceState; geben Sie "[plate] set to maintenance" oder "Vehicle not found" zurück
  • main.php — Binden Sie die RentalService- und Customer-Dateien ein. Sie erhalten drei Eingaben: Flottendaten (JSON), Kundendaten (JSON) und Operationen (JSON).

    Format des Flotten-JSON:

    [{"type": "car", "plate": "CAR-001", "brand": "Toyota", "rate": 50}, {"type": "van", "plate": "VAN-001", "brand": "Ford", "rate": 80, "mileage_rate": 0.25}]

    Format des Kunden-JSON:

    {"id": 1, "name": "Alice"}

    Format des Operationen-JSON:

    [{"op": "available"}, {"op": "rent", "plate": "CAR-001", "days": 3}, {"op": "complete", "plate": "CAR-001"}, {"op": "maintenance", "plate": "VAN-001"}, {"op": "customer_stats"}]

    Erstellen Sie den Rental Service, fügen Sie alle Fahrzeuge zur Flotte hinzu und erstellen Sie den Kunden. Behalten Sie aktive Vermietungen pro Kennzeichen im Auge. Verarbeiten Sie jede Operation:

    • "available" — Geben Sie "Available vehicles: [count]" aus
    • "rent" — Vermieten Sie das Fahrzeug; falls erfolgreich, speichern Sie das Rental-Objekt und geben Sie "Rented [plate] for [days] days" aus; falls es ein Van ist, beziehen Sie miles aus der Operation mit ein; andernfalls geben Sie die Fehlermeldung aus
    • "complete" — Schließen Sie die gespeicherte Vermietung für dieses Kennzeichen ab; geben Sie das Ergebnis aus
    • "maintenance" — Geben Sie das Ergebnis von setMaintenance() aus
    • "status" — Geben Sie "[plate]: [status]" für das angegebene Kennzeichen aus
    • "customer_stats" — Geben Sie "[name]: [count] rentals, $[total] spent" aus (2 Dezimalstellen)

    Geben Sie jedes Ergebnis in einer neuen Zeile aus.

Dieses System zeigt, wie das State-Pattern die Fahrzeugverfügbarkeit elegant ohne komplexe Bedingungen handhabt, wie Vererbung eine saubere Fahrzeughierarchie mit polymorpher Preisgestaltung schafft und wie Kapselung die Integrität der Mietdaten während des gesamten Workflows schützt.

Probier es selbst

<?php

require_once 'RentalService.php';
require_once 'Customer.php';

// Eingaben lesen
$fleetJson = trim(fgets(STDIN));
$customerJson = trim(fgets(STDIN));
$operationsJson = trim(fgets(STDIN));

// JSON-Daten parsen
$fleetData = (array)json_decode($fleetJson, true);
$customerData = (array)json_decode($customerJson, true);
$operations = (array)json_decode($operationsJson, true);

// TODO: RentalService-Instanz erstellen

// TODO: Alle Fahrzeuge basierend auf dem Typ zur Flotte hinzufügen:
// - "car" -> new Car(plate, brand, rate)
// - "motorcycle" -> new Motorcycle(plate, brand, rate)
// - "van" -> new Van(plate, brand, rate, mileage_rate)

// TODO: Customer-Instanz aus customerData erstellen

// TODO: Array erstellen, um aktive Vermietungen nach Kennzeichen zu verfolgen
$activeRentals = [];

// TODO: Jede Operation verarbeiten und Ergebnisse ausgeben:
// - "available": "Available vehicles: [count]" ausgeben
// - "rent": Fahrzeug mieten, Rental speichern falls erfolgreich, Ergebnis ausgeben
// - "complete": Vermietung abschließen, Ergebnis ausgeben
// - "maintenance": Wartung setzen, Ergebnis ausgeben
// - "status": "[plate]: [status]" ausgeben
// - "customer_stats": "[name]: [count] rentals, $[total] spent" ausgeben

foreach ($operations as $op) {
    $operation = (array)$op;
    $opType = $operation['op'];
    
    // TODO: Jeden Operationstyp verarbeiten
    switch ($opType) {
        case 'available':
            // TODO: Anzahl der verfügbaren Fahrzeuge ausgeben
            break;
        case 'rent':
            // TODO: Fahrzeug mieten und Ergebnis ausgeben
            break;
        case 'complete':
            // TODO: Vermietung abschließen und Ergebnis ausgeben
            break;
        case 'maintenance':
            // TODO: Wartung setzen und Ergebnis ausgeben
            break;
        case 'status':
            // TODO: Fahrzeugstatus ausgeben
            break;
        case 'customer_stats':
            // TODO: Kundenstatistiken ausgeben
            break;
    }
}

?>

Alle Lektionen in Objektorientierte Programmierung