Usługa wynajmu pojazdów
Część sekcji Programowanie obiektowe ścieżki PHP w Coddy. Lekcja 91 z 91.
Wyzwanie
ŁatwyStwórzmy system usług wynajmu pojazdów, który zarządza flotą pojazdów, śledzi wynajmy klientów i oblicza ceny na podstawie typu pojazdu. To kompleksowe wyzwanie łączy dziedziczenie, interfejsy, hermetyzację i wzorzec projektowy State, aby stworzyć realistyczną aplikację do obsługi wypożyczalni.
Rozmieścisz kod w siedmiu plikach:
VehicleState.php: Zdefiniuj interfejsVehicleState, który reprezentuje różne stany pojazdu. Uwzględnij dwie metody:getStatus(): stringicanRent(): bool. Następnie utwórz trzy klasy implementujące ten interfejs:AvailableState: zwraca"Available"itrueRentedState: zwraca"Rented"ifalseMaintenanceState: zwraca"Maintenance"ifalse
Vehicle.php: Dołącz plik VehicleState. Utwórz abstrakcyjną klasęVehiclez promocją parametrów konstruktora dlalicensePlate(string, public readonly),brand(string, public readonly) idailyRate(float, protected). Przechowuj bieżący stan we właściwości prywatnej, której domyślną wartością jestAvailableState. Zaimplementuj:getState(): VehicleState: zwraca bieżący stansetState(VehicleState $state): void: zmienia stangetStatus(): string: deleguje dogetStatus()stanucanRent(): bool: deleguje docanRent()stanuabstract calculateCost(int $days): float: każdy typ pojazdu oblicza koszt inaczejgetType(): string: zwraca nazwę klasy za pomocąstatic::class
Vehicles.php: Dołącz plik Vehicle. Utwórz trzy konkretne klasy pojazdów:Car: dziedziczy po Vehicle;calculateCost()zwracadailyRate * daysMotorcycle: dziedziczy po Vehicle;calculateCost()zwracadailyRate * days * 0.8(20% zniżki)Van: dziedziczy po Vehicle i ma dodatkowy parametr$mileageRate(float);calculateCost(int $days, int $miles = 0)zwraca(dailyRate * days) + (mileageRate * miles)
Customer.php: Utwórz klasęCustomerz promocją parametrów konstruktora dlaid(int, public readonly) iname(string, public readonly). Przechowuj historię wynajmów w prywatnej tablicy. Zaimplementuj:addRental(string $vehiclePlate, float $cost): void: dodaje wpis do historiigetRentalCount(): int: zwraca liczbę wynajmówgetTotalSpent(): float: zwraca sumę kosztów wszystkich wynajmów
Rental.php: Dołącz pliki Vehicle i Customer. Utwórz klasęRental, która łączy klienta z pojazdem. Użyj promocji parametrów konstruktora dlacustomer(Customer, public readonly),vehicle(Vehicle, public readonly),days(int, private) oraz opcjonalniemiles(int, private, domyślnie 0). Zaimplementuj:calculateTotal(): float: jeśli pojazd jest typu Van, przekaż liczbę mil docalculateCost(); w przeciwnym razie przekaż tylko liczbę dnicomplete(): string: oblicza sumę, dodaje ją do historii klienta, ustawia stan pojazdu na AvailableState i zwraca"Rental completed: $[total]"(2 miejsca po przecinku)
RentalService.php: Dołącz pliki Rental i Vehicles. Utwórz klasęRentalService, która zarządza flotą. Przechowuj pojazdy w prywatnej tablicy indeksowanej numerami rejestracyjnymi. Zaimplementuj:addVehicle(Vehicle $vehicle): void: dodaje pojazd do flotyfindVehicle(string $plate): ?Vehicle: zwraca pojazd lub nullgetAvailableVehicles(): array: zwraca pojazdy, dla którychcanRent()ma wartość truerentVehicle(Customer $customer, string $plate, int $days, int $miles = 0): string|Rental: jeśli pojazdu nie znaleziono, zwróć"Vehicle not found"; jeśli jest niedostępny, zwróć"Vehicle is not available"; w przeciwnym razie ustaw stan pojazdu na RentedState i zwróć nowy obiekt RentalsetMaintenance(string $plate): string: ustawia stan pojazdu na MaintenanceState; zwróć"[plate] set to maintenance"lub"Vehicle not found"
main.php: Dołącz pliki RentalService i Customer. Otrzymasz trzy dane wejściowe: dane floty (JSON), dane klienta (JSON) i operacje (JSON).Format JSON floty:
[{"type": "car", "plate": "CAR-001", "brand": "Toyota", "rate": 50}, {"type": "van", "plate": "VAN-001", "brand": "Ford", "rate": 80, "mileage_rate": 0.25}]Format JSON klienta:
{"id": 1, "name": "Alice"}Format JSON operacji:
[{"op": "available"}, {"op": "rent", "plate": "CAR-001", "days": 3}, {"op": "complete", "plate": "CAR-001"}, {"op": "maintenance", "plate": "VAN-001"}, {"op": "customer_stats"}]Utwórz usługę wynajmu, dodaj wszystkie pojazdy do floty i utwórz klienta. Śledź aktywne wynajmy według numerów rejestracyjnych. Przetwórz każdą operację:
"available": wypisz"Available vehicles: [count]""rent": wynajmij pojazd; jeśli się uda, zapisz obiekt Rental i wypisz"Rented [plate] for [days] days"; jeśli pojazd to Van, uwzględnij liczbę mil z operacji; w przeciwnym razie wypisz komunikat o błędzie"complete": zakończ zapisany wynajem dla danego numeru rejestracyjnego; wypisz wynik"maintenance": wypisz wyniksetMaintenance()"status": wypisz"[plate]: [status]"dla podanego numeru rejestracyjnego"customer_stats": wypisz"[name]: [count] rentals, $[total] spent"(2 miejsca po przecinku)
Wypisz każdy wynik w nowym wierszu.
Ten system pokazuje, jak wzorzec State elegancko obsługuje dostępność pojazdów bez skomplikowanych instrukcji warunkowych, jak dziedziczenie tworzy przejrzystą hierarchię pojazdów z polimorficznym ustalaniem cen oraz jak hermetyzacja chroni integralność danych o wynajmach na każdym etapie procesu.
Spróbuj swoich sił
<?php
require_once 'RentalService.php';
require_once 'Customer.php';
// Odczytaj dane wejściowe
$fleetJson = trim(fgets(STDIN));
$customerJson = trim(fgets(STDIN));
$operationsJson = trim(fgets(STDIN));
// Przetwórz dane JSON
$fleetData = (array)json_decode($fleetJson, true);
$customerData = (array)json_decode($customerJson, true);
$operations = (array)json_decode($operationsJson, true);
// TODO: Utwórz instancję RentalService
// TODO: Dodaj wszystkie pojazdy do floty na podstawie typu:
// - "car" -> new Car(plate, brand, rate)
// - "motorcycle" -> new Motorcycle(plate, brand, rate)
// - "van" -> new Van(plate, brand, rate, mileage_rate)
// TODO: Utwórz instancję Customer na podstawie customerData
// TODO: Utwórz tablicę do śledzenia aktywnych wypożyczeń według plate
$activeRentals = [];
// TODO: Przetwórz każdą operację i wypisz wyniki:
// - "available": Wypisz "Available vehicles: [count]"
// - "rent": Wypożycz pojazd, w razie powodzenia zapisz Rental i wypisz wynik
// - "complete": Zakończ wynajem i wypisz wynik
// - "maintenance": Ustaw tryb serwisowy i wypisz wynik
// - "status": Wypisz "[plate]: [status]"
// - "customer_stats": Wypisz "[name]: [count] rentals, $[total] spent"
foreach ($operations as $op) {
$operation = (array)$op;
$opType = $operation['op'];
// TODO: Obsłuż każdy typ operacji
switch ($opType) {
case 'available':
// TODO: Wypisz liczbę dostępnych pojazdów
break;
case 'rent':
// TODO: Wynajmij pojazd i wypisz wynik
break;
case 'complete':
// TODO: Zakończ wynajem i wypisz wynik
break;
case 'maintenance':
// TODO: Ustaw tryb serwisowy i wypisz wynik
break;
case 'status':
// TODO: Wypisz status pojazdu
break;
case 'customer_stats':
// TODO: Wypisz statystyki klienta
break;
}
}
?>Wszystkie lekcje w sekcji Programowanie obiektowe
1Podstawy programowania obiektowego
Pliki zewnętrzneWprowadzenie do programowania obiektowegoKlasy a obiektySłowo kluczowe $thisMetodyWłaściwościKonstruktor (__construct)Destruktor (__destruct)Powtórka — prosty kalkulator4Dziedziczenie
Podstawy dziedziczeniaSłowo kluczowe parent::Przesłanianie metodSłowo kluczowe finalKlasy abstrakcyjnePowtórzenie – hierarchia pracowników7Enkapsulacja
Public, protected, privateModyfikatory dostępu w szczegółachGettery i setteryUkrywanie informacjiPromocja parametrów konstruktora (8.0)Podsumowanie — system ewidencji studentów2Przestrzenie nazw i autoloading
Wprowadzenie do przestrzeni nazwSłowo kluczowe useStandard autoloadingu PSR-4Autoloader ComposeraPodsumowanie – uporządkowany projekt5Interfejsy i kontrakty
Wprowadzenie do interfejsówImplementowanie interfejsówImplementowanie wielu interfejsówInterfejs a klasa abstrakcyjnaPodpowiadanie typów za pomocą interfejsówPodsumowanie — kalkulator kształtów8Metody magiczne
Wprowadzenie do metod magicznych__toString i __debugInfo__get, __set, __isset, __unset__call i __callStatic__clone i klonowanie obiektów__serialize i __unserializePodsumowanie — własna kolekcja11System typów i obsługa błędów
Deklaracje typówTypy nullableTypy sumy i przecięciaKlasy wyjątkówNiestandardowa hierarchia wyjątkówTry, Catch, FinallyPodsumowanie — walidator formularzy14Projekt: Zarządzanie biblioteką
Przegląd projektuKlasy książki i użytkownika3Właściwości klas
Właściwości instancji a właściwości statyczneStałe w klasachMetody i właściwości statyczneWłaściwości prywatne i chronioneWłaściwości tylko do odczytu (PHP 8.1)Podsumowanie — menedżer kont bankowych6Polimorfizm
Ponowne omówienie nadpisywania metodPolimorfizm za pomocą interfejsówPodpowiedzi typów i typy sumyPóźne wiązanie statycznePodsumowanie — procesor płatności9Cechy
Wprowadzenie do cechKorzystanie z wielu cechRozwiązywanie konfliktów cechMetody abstrakcyjne w cechachCechy a dziedziczenie12Wzorce projektowe, część 1
Wprowadzenie do wzorców projektowychWzorzec SingletonWzorzec FactoryWzorzec ObserverWzorzec Strategy15Wyzwania końcowe
Platforma e-learningowaSystem bankowyTworzenie postaci do gryUsługa wynajmu pojazdówPoćwicz samodzielnie: Kompilator PHP online