Fahrzeugvermietung
Teil des Abschnitts Objektorientierte Programmierung der PHP-Journey von Coddy. Lektion 91 von 91.
Aufgabe
EinfachErstellen wir ein Fahrzeugvermietungssystem, das eine Fahrzeugflotte verwaltet, Kundenmietvorgänge verfolgt und Preise basierend auf dem Fahrzeugtyp berechnet. Diese umfassende Herausforderung bringt Vererbung, Schnittstellen, Kapselung und das Zustandsmuster zusammen, um eine realistische Anwendung für ein Vermietungsgeschäft zu erstellen.
Du organisierst deinen Code über sieben Dateien:
VehicleState.php: Definiere eineVehicleState-Schnittstelle, die die verschiedenen Zustände repräsentiert, in denen sich ein Fahrzeug befinden kann. Füge zwei Methoden hinzu:getStatus(): stringundcanRent(): bool. Erstelle anschließend drei Klassen, die diese Schnittstelle implementieren:AvailableState: gibt"Available"undtruezurückRentedState: gibt"Rented"undfalsezurückMaintenanceState: gibt"Maintenance"undfalsezurück
Vehicle.php: Binde die Datei Vehicle ein. Erstelle eine abstrakte KlasseVehiclemit Konstruktor-Promotion fürlicensePlate(string, public readonly),brand(string, public readonly) unddailyRate(float, protected). Speichere den aktuellen Zustand in einer privaten Eigenschaft, die standardmäßig aufAvailableStategesetzt wird. Implementiere:getState(): VehicleState: gibt den aktuellen Zustand zurücksetState(VehicleState $state): void: ändert den ZustandgetStatus(): string: delegiert angetStatus()des ZustandscanRent(): bool: delegiert ancanRent()des Zustandsabstract calculateCost(int $days): float: jeder Fahrzeugtyp berechnet die Kosten unterschiedlichgetType(): string: gibt den Klassennamen mithilfe vonstatic::classzurück
Vehicles.php: Binde die Datei Vehicle ein. Erstelle drei konkrete Fahrzeugklassen:Car: erweitert Vehicle;calculateCost()gibtdailyRate * dayszurückMotorcycle: erweitert Vehicle;calculateCost()gibtdailyRate * days * 0.8zurü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: Erstelle eine KlasseCustomermit Konstruktor-Promotion fürid(int, public readonly) undname(string, public readonly). Verfolge die Miethistorie in einem privaten Array. Implementiere:addRental(string $vehiclePlate, float $cost): void: fügt einen Eintrag zur Historie hinzugetRentalCount(): int: gibt die Anzahl der Mietvorgänge zurückgetTotalSpent(): float: gibt die Summe aller Mietkosten zurück
Rental.php: Binde die Dateien Vehicle und Customer ein. Erstelle eine KlasseRental, die einen Kunden mit einem Fahrzeug verknüpft. Verwende Konstruktor-Promotion fürcustomer(Customer, public readonly),vehicle(Vehicle, public readonly),days(int, private) und optionalmiles(int, private, default 0). Implementiere:calculateTotal(): float: Wenn das Fahrzeug ein Van ist, übergib miles ancalculateCost(); andernfalls übergib nur dayscomplete(): 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: Binde die Dateien Rental und Vehicles ein. Erstelle eine KlasseRentalService, die die Fahrzeugflotte verwaltet. Speichere Fahrzeuge in einem privaten Array, das nach dem Kennzeichen indiziert ist. Implementiere:addVehicle(Vehicle $vehicle): void: fügt ein Fahrzeug zur Flotte hinzufindVehicle(string $plate): ?Vehicle: gibt das Fahrzeug oder null zurückgetAvailableVehicles(): array: gibt Fahrzeuge zurück, für diecanRent()true istrentVehicle(Customer $customer, string $plate, int $days, int $miles = 0): string|Rental: Wenn das Fahrzeug nicht gefunden wird, gib"Vehicle not found"zurück; wenn es nicht verfügbar ist, gib"Vehicle is not available"zurück; andernfalls setze das Fahrzeug auf RentedState und gib ein neues Rental-Objekt zurücksetMaintenance(string $plate): string: setzt das Fahrzeug auf MaintenanceState; gibt"[plate] set to maintenance"oder"Vehicle not found"zurück
main.php: Binde die Dateien RentalService und Customer ein. Du erhältst drei Eingaben: Flottendaten (JSON), Kundendaten (JSON) und Vorgänge (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 Vorgänge-JSON:
[{"op": "available"}, {"op": "rent", "plate": "CAR-001", "days": 3}, {"op": "complete", "plate": "CAR-001"}, {"op": "maintenance", "plate": "VAN-001"}, {"op": "customer_stats"}]Erstelle den Vermietungsdienst, füge alle Fahrzeuge zur Flotte hinzu und erstelle den Kunden. Verfolge aktive Mietvorgänge nach Kennzeichen. Verarbeite jeden Vorgang:
"available": Gib"Available vehicles: [count]"aus"rent": Miete das Fahrzeug; wenn dies erfolgreich ist, speichere das Rental und gib"Rented [plate] for [days] days"aus; wenn es sich um einen Van handelt, füge miles aus dem Vorgang ein; andernfalls gib die Fehlermeldung aus"complete": Schließe den gespeicherten Mietvorgang für dieses Kennzeichen ab; gib das Ergebnis aus"maintenance": Gib das Ergebnis vonsetMaintenance()aus"status": Gib für das angegebene Kennzeichen"[plate]: [status]"aus"customer_stats": Gib"[name]: [count] rentals, $[total] spent"aus (2 Dezimalstellen)
Gib jedes Ergebnis in einer neuen Zeile aus.
Dieses System zeigt, wie das Zustandsmuster die Fahrzeugverfügbarkeit elegant ohne komplexe Bedingungen verwaltet, wie Vererbung eine übersichtliche Fahrzeughierarchie mit polymorpher Preisberechnung erstellt und wie Kapselung die Integrität der Mietdaten während des gesamten Ablaufs 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 plate zu verfolgen
$activeRentals = [];
// TODO: Jede Operation verarbeiten und Ergebnisse ausgeben:
// - "available": Print "Available vehicles: [count]"
// - "rent": Fahrzeug mieten, Rental speichern falls erfolgreich, Ergebnis ausgeben
// - "complete": Die 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 behandeln
switch ($opType) {
case 'available':
// TODO: Print available vehicle count
break;
case 'rent':
// TODO: Fahrzeug mieten und Ergebnis ausgeben
break;
case 'complete':
// TODO: Miete 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
1Grundlagen der OOP
Externe DateienEinführung in OOPKlassen vs. ObjekteDas Schlüsselwort $thisMethodenEigenschaftenKonstruktor (__construct)Destruktor (__destruct)Rückblick – Einfacher Taschenrechner4Vererbung
Grundlegende VererbungDas Schlüsselwort parent::MethodenüberschreibungDas Schlüsselwort finalAbstrakte KlassenRückblick – Mitarbeiterhierarchie7Kapselung
Öffentlich, geschützt, privatZugriffsmodifikatoren im DetailGetter und SetterInformationsverbergungKonstruktor-Promotion (8.0)Wiederholung – System zur Verwaltung von Schülerdatensätzen2Namespaces & Autoloading
Einführung in NamespacesDas use-SchlüsselwortPSR-4-Autoloading-StandardComposer-AutoloaderRückblick – Organisiertes Projekt5Schnittstellen & Verträge
Einführung in SchnittstellenSchnittstellen implementierenMehrere Schnittstellen implementierenSchnittstelle vs. abstrakte KlasseTyp-Hinweise mit SchnittstellenRückblick – Formrechner8Magische Methoden
Einführung in magische Methoden__toString & __debugInfo__get, __set, __isset, __unset__call & __callStatic__clone & Objektklonen__serialize & __unserializeRückblick – Benutzerdefinierte Sammlung11Typsystem & Fehlerbehandlung
TypdeklarationenNullable-TypenUnion- & Intersection-TypenException-KlassenBenutzerdefinierte Exception-HierarchieTry, Catch, FinallyRückblick – Formularvalidator14Projekt: Bibliotheksverwaltung
ProjektübersichtBuch- und Benutzerklassen3Klassen-Eigenschaften
Instanz- vs. statische EigenschaftenKonstanten in KlassenStatische Methoden & EigenschaftenPrivate & geschützte EigenschaftenSchreibgeschützte Eigenschaften (PHP 8.1)Zusammenfassung – Bankkonto-Manager6Polymorphie
Methodenüberschreibung erneut betrachtetPolymorphie über SchnittstellenTyp-Hinweise & Union-TypenSpätes statisches BindenRückblick – Zahlungsabwickler9Traits
Einführung in TraitsMehrere Traits verwendenAuflösung von Trait-KonfliktenAbstrakte Methoden in TraitsTraits vs. Vererbung12Entwurfsmuster Teil 1
Einführung in EntwurfsmusterSingleton-MusterFactory-MusterObserver-MusterStrategy-Muster15Abschließende Herausforderungen
E-Learning-PlattformBankingsystemEntwicklung einer SpielfigurFahrzeugvermietungÜbe selbstständig: Online-PHP-Compiler