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 с продвижением конструктора (constructor promotion) для 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, передайте мили в calculateCost(); в противном случае передайте только дни
    • complete(): string — рассчитывает общую сумму, добавляет её в историю клиента, переводит транспортное средство в AvailableState, возвращает "Rental completed: $[total]" (с 2 знаками после запятой)
  • RentalService.php — Подключите файлы Rental и Vehicles. Создайте класс RentalService, который управляет автопарком. Храните транспортные средства в приватном массиве, индексированном по номерному знаку. Реализуйте:
    • addVehicle(Vehicle $vehicle): void — добавляет транспортное средство в парк
    • findVehicle(string $plate): ?Vehicle — возвращает транспортное средство или null
    • getAvailableVehicles(): array — возвращает транспортные средства, для которых canRent() истинно
    • 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, включить мили из операции; в противном случае вывести сообщение об ошибке
    • "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: Создать массив для отслеживания активных аренд по номерному знаку
$activeRentals = [];

// TODO: Обработать каждую операцию и вывести результаты:
// - "available": Вывести "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: Вывести количество доступных транспортных средств
            break;
        case 'rent':
            // TODO: Арендовать транспортное средство и вывести результат
            break;
        case 'complete':
            // TODO: Завершить аренду и вывести результат
            break;
        case 'maintenance':
            // TODO: Установить техническое обслуживание и вывести результат
            break;
        case 'status':
            // TODO: Вывести статус транспортного средства
            break;
        case 'customer_stats':
            // TODO: Вывести статистику клиента
            break;
    }
}

?>

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

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