Menu
Coddy logo textTech

Usługa wynajmu pojazdów

Część sekcji Programowanie obiektowe ścieżki PHP w Coddy. Lekcja 91 z 91.

challenge icon

Wyzwanie

Łatwy

Stwó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 interfejs VehicleState, który reprezentuje różne stany pojazdu. Uwzględnij dwie metody: getStatus(): string i canRent(): bool. Następnie utwórz trzy klasy implementujące ten interfejs:
    • AvailableState: zwraca "Available" i true
    • RentedState: zwraca "Rented" i false
    • MaintenanceState: zwraca "Maintenance" i false
  • Vehicle.php: Dołącz plik VehicleState. Utwórz abstrakcyjną klasę Vehicle z promocją parametrów konstruktora dla licensePlate (string, public readonly), brand (string, public readonly) i dailyRate (float, protected). Przechowuj bieżący stan we właściwości prywatnej, której domyślną wartością jest AvailableState. Zaimplementuj:
    • getState(): VehicleState: zwraca bieżący stan
    • setState(VehicleState $state): void: zmienia stan
    • getStatus(): string: deleguje do getStatus() stanu
    • canRent(): bool: deleguje do canRent() stanu
    • abstract calculateCost(int $days): float: każdy typ pojazdu oblicza koszt inaczej
    • getType(): 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() zwraca dailyRate * days
    • Motorcycle: dziedziczy po Vehicle; calculateCost() zwraca dailyRate * 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ę Customer z promocją parametrów konstruktora dla id (int, public readonly) i name (string, public readonly). Przechowuj historię wynajmów w prywatnej tablicy. Zaimplementuj:
    • addRental(string $vehiclePlate, float $cost): void: dodaje wpis do historii
    • getRentalCount(): int: zwraca liczbę wynajmów
    • getTotalSpent(): 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 dla customer (Customer, public readonly), vehicle (Vehicle, public readonly), days (int, private) oraz opcjonalnie miles (int, private, domyślnie 0). Zaimplementuj:
    • calculateTotal(): float: jeśli pojazd jest typu Van, przekaż liczbę mil do calculateCost(); w przeciwnym razie przekaż tylko liczbę dni
    • complete(): 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 floty
    • findVehicle(string $plate): ?Vehicle: zwraca pojazd lub null
    • getAvailableVehicles(): array: zwraca pojazdy, dla których canRent() ma wartość true
    • rentVehicle(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 Rental
    • setMaintenance(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 wynik setMaintenance()
    • "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

Poćwicz samodzielnie: Kompilator PHP online