Сервис аренды транспортных средств
Часть раздела Объектно-ориентированное программирование путешествия по PHP на Coddy. Урок 91 из 91.
Задание
ЛегкоДавайте создадим систему Vehicle Rental Service, которая управляет автопарком, отслеживает аренды клиентов и рассчитывает стоимость на основе типа транспортного средства. Эта комплексная задача объединяет наследование, интерфейсы, инкапсуляцию и паттерн State для создания реалистичного приложения бизнеса по аренде.
Вы организуете код в семи файлах:
VehicleState.php: определите интерфейсVehicleState, представляющий различные состояния, в которых может находиться транспортное средство. Включите два метода:getStatus(): stringиcanRent(): bool. Затем создайте три класса, реализующих этот интерфейс:AvailableState: возвращает"Available"иtrueRentedState: возвращает"Rented"иfalseMaintenanceState: возвращает"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 * daysMotorcycle: наследуется от 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(); в противном случае передайте только dayscomplete(): string: рассчитывает итоговую стоимость, добавляет её в историю клиента, устанавливает для транспортного средства AvailableState и возвращает"Rental completed: $[total]"(2 знака после запятой)
RentalService.php: подключите файлы Rental и Vehicles. Создайте классRentalService, управляющий автопарком. Храните транспортные средства в закрытом массиве, индексированном по номерному знаку. Реализуйте:addVehicle(Vehicle $vehicle): void: добавляет транспортное средство в автопаркfindVehicle(string $plate): ?Vehicle: возвращает транспортное средство или nullgetAvailableVehicles(): array: возвращает транспортные средства, для которыхcanRent()имеет значение truerentVehicle(Customer $customer, string $plate, int $days, int $miles = 0): string|Rental: если транспортное средство не найдено, верните"Vehicle not found"; если оно недоступно, верните"Vehicle is not available"; в противном случае установите для транспортного средства RentedState и верните новый объект RentalsetMaintenance(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;
}
}
?>Все уроки раздела Объектно-ориентированное программирование
1Основы ООП
Внешние файлыВведение в ООПКлассы и объектыКлючевое слово $thisМетодыСвойстваКонструктор (__construct)Деструктор (__destruct)Повторение — простой калькулятор4Наследование
Основы наследованияКлючевое слово parent::Переопределение методовКлючевое слово finalАбстрактные классыПовторение — иерархия сотрудников7Инкапсуляция
Public, Protected, PrivateМодификаторы доступа подробноГеттеры и сеттерыСокрытие информацииПродвижение конструктора (8.0)Повторение — система учёта студентов2Пространства имён и автозагрузка
Введение в пространства имёнКлючевое слово useСтандарт автозагрузки PSR-4Автозагрузчик ComposerПовторение — структурированный проект5Интерфейсы и контракты
Введение в интерфейсыРеализация интерфейсовРеализация нескольких интерфейсовИнтерфейс и абстрактный классАннотация типов с интерфейсамиПовторение — калькулятор фигур8Магические методы
Введение в магические методы__toString и __debugInfo__get, __set, __isset, __unset__call и __callStatic__clone и клонирование объектов__serialize и __unserializeПовторение — пользовательская коллекция3Свойства классов
Свойства экземпляра и статические свойстваКонстанты в классахСтатические методы и свойстваПриватные и защищённые свойстваСвойства только для чтения (PHP 8.1)Повторение — менеджер банковского счёта6Полиморфизм
Повторение переопределения методовПолиморфизм через интерфейсыАннотации типов и объединённые типыПозднее статическое связываниеПовторение — обработчик платежей9Трейты
Введение в трейтыИспользование нескольких трейтовРазрешение конфликтов трейтовАбстрактные методы в трейтахТрейты и наследование12Паттерны проектирования, часть 1
Введение в паттерны проектированияПаттерн SingletonПаттерн FactoryПаттерн ObserverПаттерн Strategy15Финальные задания
Платформа электронного обученияБанковская системаРазработка игрового персонажаСервис аренды транспортных средствПотренируйтесь самостоятельно: Онлайн-компилятор PHP