Menu
Coddy logo textTech

Сервис аренды транспортных средств

Часть раздела Объектно-ориентированное программирование путешествия по PHP на Coddy. Урок 91 из 91.

challenge icon

Задание

Легко

Давайте создадим систему Vehicle Rental Service, которая управляет автопарком, отслеживает аренды клиентов и рассчитывает стоимость на основе типа транспортного средства. Эта комплексная задача объединяет наследование, интерфейсы, инкапсуляцию и паттерн State для создания реалистичного приложения бизнеса по аренде.

Вы организуете код в семи файлах:

  • VehicleState.php: определите интерфейс VehicleState, представляющий различные состояния, в которых может находиться транспортное средство. Включите два метода: getStatus(): string и canRent(): bool. Затем создайте три класса, реализующих этот интерфейс:
    • AvailableState: возвращает "Available" и true
    • RentedState: возвращает "Rented" и false
    • MaintenanceState: возвращает "Maintenance" и false
  • Vehicle.php: подключите файл VehicleState. Создайте абстрактный класс Vehicle с продвижением параметров конструктора для licensePlate (string, public readonly), brand (string, public readonly) и dailyRate (float, protected). Храните текущее состояние в закрытом свойстве, по умолчанию устанавливая AvailableState. Реализуйте:
    • getState(): VehicleState: возвращает текущее состояние
    • setState(VehicleState $state): void: изменяет состояние
    • getStatus(): string: делегирует вызов getStatus() состояния
    • canRent(): bool: делегирует вызов canRent() состояния
    • abstract calculateCost(int $days): float: каждый тип транспортного средства рассчитывает стоимость по-своему
    • getType(): string: возвращает имя класса с использованием static::class
  • Vehicles.php: подключите файл Vehicle. Создайте три конкретных класса транспортных средств:
    • Car: наследуется от Vehicle; calculateCost() возвращает dailyRate * days
    • Motorcycle: наследуется от Vehicle; calculateCost() возвращает dailyRate * days * 0.8 (скидка 20%)
    • Van: наследуется от Vehicle и имеет дополнительный параметр $mileageRate (float); calculateCost(int $days, int $miles = 0) возвращает (dailyRate * days) + (mileageRate * miles)
  • Customer.php: создайте класс Customer с продвижением параметров конструктора для id (int, public readonly) и name (string, public readonly). Храните историю аренд в закрытом массиве. Реализуйте:
    • addRental(string $vehiclePlate, float $cost): void: добавляет запись в историю
    • getRentalCount(): int: возвращает количество аренд
    • getTotalSpent(): float: возвращает сумму стоимости всех аренд
  • Rental.php: подключите файлы Vehicle и Customer. Создайте класс Rental, связывающий клиента с транспортным средством. Используйте продвижение параметров конструктора для customer (Customer, public readonly), vehicle (Vehicle, public readonly), days (int, private) и необязательного miles (int, private, по умолчанию 0). Реализуйте:
    • calculateTotal(): float: если транспортное средство является Van, передайте miles в calculateCost(); в противном случае передайте только days
    • complete(): string: рассчитывает итоговую стоимость, добавляет её в историю клиента, устанавливает для транспортного средства AvailableState и возвращает "Rental completed: $[total]" (2 знака после запятой)
  • RentalService.php: подключите файлы Rental и Vehicles. Создайте класс RentalService, управляющий автопарком. Храните транспортные средства в закрытом массиве, индексированном по номерному знаку. Реализуйте:
    • addVehicle(Vehicle $vehicle): void: добавляет транспортное средство в автопарк
    • findVehicle(string $plate): ?Vehicle: возвращает транспортное средство или null
    • getAvailableVehicles(): array: возвращает транспортные средства, для которых canRent() имеет значение true
    • rentVehicle(Customer $customer, string $plate, int $days, int $miles = 0): string|Rental: если транспортное средство не найдено, верните "Vehicle not found"; если оно недоступно, верните "Vehicle is not available"; в противном случае установите для транспортного средства RentedState и верните новый объект Rental
    • setMaintenance(string $plate): string: устанавливает для транспортного средства MaintenanceState; возвращает "[plate] set to maintenance" или "Vehicle not found"
  • main.php: подключите файлы RentalService и Customer. Вы получите три входных значения: данные автопарка (JSON), данные клиента (JSON) и операции (JSON).

    Формат JSON автопарка:

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

    Формат JSON клиента:

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

    Формат JSON операций:

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

    Создайте службу аренды, добавьте все транспортные средства в автопарк и создайте клиента. Отслеживайте активные аренды по номерному знаку. Обработайте каждую операцию:

    • "available": выведите "Available vehicles: [count]"
    • "rent": арендуйте транспортное средство; если операция успешна, сохраните Rental и выведите "Rented [plate] for [days] days"; если это Van, включите miles из операции; в противном случае выведите сообщение об ошибке
    • "complete": завершите сохранённую аренду для этого номерного знака; выведите результат
    • "maintenance": выведите результат setMaintenance()
    • "status": выведите "[plate]: [status]" для указанного номерного знака
    • "customer_stats": выведите "[name]: [count] rentals, $[total] spent" (2 знака после запятой)

    Выводите каждый результат с новой строки.

Эта система демонстрирует, как паттерн State элегантно управляет доступностью транспортных средств без сложных условных конструкций, как наследование создаёт понятную иерархию транспортных средств с полиморфным расчётом стоимости и как инкапсуляция защищает целостность данных об аренде на протяжении всего рабочего процесса.

Попробуйте сами

<?php

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

// Прочитать входные данные
$fleetJson = trim(fgets(STDIN));
$customerJson = trim(fgets(STDIN));
$operationsJson = trim(fgets(STDIN));

// Разобрать данные JSON
$fleetData = (array)json_decode($fleetJson, true);
$customerData = (array)json_decode($customerJson, true);
$operations = (array)json_decode($operationsJson, true);

// TODO: Создать экземпляр RentalService

// TODO: Добавить все транспортные средства в автопарк в зависимости от типа:
// - "car" -> new Car(plate, brand, rate)
// - "motorcycle" -> new Motorcycle(plate, brand, rate)
// - "van" -> new Van(plate, brand, rate, mileage_rate)

// TODO: Создать экземпляр Customer из customerData

// TODO: Создать массив для отслеживания активных аренд по plate
$activeRentals = [];

// TODO: Обработать каждую операцию и вывести результаты:
// - "available": Print "Available vehicles: [count]"
// - "rent": Арендовать транспортное средство, сохранить Rental при успехе, вывести результат
// - "complete": Завершить аренду, вывести результат
// - "maintenance": Установить обслуживание, вывести результат
// - "status": Вывести "[plate]: [status]"
// - "customer_stats": Вывести "[name]: [count] rentals, $[total] spent"

foreach ($operations as $op) {
    $operation = (array)$op;
    $opType = $operation['op'];
    
    // TODO: Обработать каждый тип операции
    switch ($opType) {
        case 'available':
            // TODO: Print available vehicle count
            break;
        case 'rent':
            // TODO: Арендовать транспортное средство и вывести результат
            break;
        case 'complete':
            // TODO: Завершить аренду и вывести результат
            break;
        case 'maintenance':
            // TODO: Установить обслуживание и вывести результат
            break;
        case 'status':
            // TODO: Вывести статус транспортного средства
            break;
        case 'customer_stats':
            // TODO: Вывести статистику клиента
            break;
    }
}

?>

Все уроки раздела Объектно-ориентированное программирование

Потренируйтесь самостоятельно: Онлайн-компилятор PHP