Menu
Coddy logo textTech

Serviço de Aluguel de Veículos

Parte da seção Programação Orientada a Objetos do Journey de PHP da Coddy — lição 91 de 91.

challenge icon

Desafio

Fácil

Vamos construir um sistema de Serviço de Aluguel de Veículos que gerencia uma frota de veículos, rastreia aluguéis de clientes e calcula preços com base no tipo de veículo. Este desafio abrangente reúne herança, interfaces, encapsulamento e o padrão State para criar uma aplicação realista de negócio de aluguel.

Você organizará seu código em sete arquivos:

  • VehicleState.php — Defina uma interface VehicleState que representa os diferentes estados em que um veículo pode estar. Inclua dois métodos: getStatus(): string e canRent(): bool. Em seguida, crie três classes implementando esta interface:
    • AvailableState — retorna "Available" e true
    • RentedState — retorna "Rented" e false
    • MaintenanceState — retorna "Maintenance" e false
  • Vehicle.php — Inclua o arquivo VehicleState. Crie uma classe abstrata Vehicle com promoção de construtor para licensePlate (string, public readonly), brand (string, public readonly) e dailyRate (float, protected). Armazene o estado atual em uma propriedade privada, com o valor padrão AvailableState. Implemente:
    • getState(): VehicleState — retorna o estado atual
    • setState(VehicleState $state): void — altera o estado
    • getStatus(): string — delega para o getStatus() do estado
    • canRent(): bool — delega para o canRent() do estado
    • abstract calculateCost(int $days): float — cada tipo de veículo calcula de forma diferente
    • getType(): string — retorna o nome da classe usando static::class
  • Vehicles.php — Inclua o arquivo Vehicle. Crie três classes de veículos concretas:
    • Car — estende Vehicle; calculateCost() retorna dailyRate * days
    • Motorcycle — estende Vehicle; calculateCost() retorna dailyRate * days * 0.8 (20% de desconto)
    • Van — estende Vehicle com um parâmetro adicional $mileageRate (float); calculateCost(int $days, int $miles = 0) retorna (dailyRate * days) + (mileageRate * miles)
  • Customer.php — Crie uma classe Customer com promoção de construtor para id (int, public readonly) e name (string, public readonly). Rastreie o histórico de aluguéis em um array privado. Implemente:
    • addRental(string $vehiclePlate, float $cost): void — adiciona ao histórico
    • getRentalCount(): int — retorna o número de aluguéis
    • getTotalSpent(): float — retorna a soma de todos os custos de aluguel
  • Rental.php — Inclua os arquivos Vehicle e Customer. Crie uma classe Rental que vincula um cliente a um veículo. Use promoção de construtor para customer (Customer, public readonly), vehicle (Vehicle, public readonly), days (int, private) e, opcionalmente, miles (int, private, padrão 0). Implemente:
    • calculateTotal(): float — se o veículo for uma Van, passe miles para calculateCost(); caso contrário, passe apenas days
    • complete(): string — calcula o total, adiciona ao histórico do cliente, define o veículo como AvailableState, retorna "Rental completed: $[total]" (2 casas decimais)
  • RentalService.php — Inclua os arquivos Rental e Vehicles. Crie uma classe RentalService que gerencia a frota. Armazene os veículos em um array privado indexado pela placa (license plate). Implemente:
    • addVehicle(Vehicle $vehicle): void — adiciona à frota
    • findVehicle(string $plate): ?Vehicle — retorna o veículo ou null
    • getAvailableVehicles(): array — retorna veículos onde canRent() é true
    • rentVehicle(Customer $customer, string $plate, int $days, int $miles = 0): string|Rental — se o veículo não for encontrado, retorne "Vehicle not found"; se não estiver disponível, retorne "Vehicle is not available"; caso contrário, defina o veículo como RentedState e retorne um novo objeto Rental
    • setMaintenance(string $plate): string — define o veículo como MaintenanceState; retorne "[plate] set to maintenance" ou "Vehicle not found"
  • main.php — Inclua os arquivos RentalService e Customer. Você receberá três entradas: dados da frota (JSON), dados do cliente (JSON) e operações (JSON).

    Formato JSON da frota:

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

    Formato JSON do cliente:

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

    Formato JSON das operações:

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

    Crie o serviço de aluguel, adicione todos os veículos à frota e crie o cliente. Mantenha o controle dos aluguéis ativos por placa. Processe cada operação:

    • "available" — Imprima "Available vehicles: [count]"
    • "rent" — Alugue o veículo; se for bem-sucedido, armazene o Rental e imprima "Rented [plate] for [days] days"; se for Van, inclua miles da operação; caso contrário, imprima a mensagem de erro
    • "complete" — Conclua o aluguel armazenado para aquela placa; imprima o resultado
    • "maintenance" — Imprima o resultado de setMaintenance()
    • "status" — Imprima "[plate]: [status]" para a placa fornecida
    • "customer_stats" — Imprima "[name]: [count] rentals, $[total] spent" (2 casas decimais)

    Imprima cada resultado em uma nova linha.

Este sistema demonstra como o padrão State lida elegantemente com a disponibilidade de veículos sem condicionais complexas, como a herança cria uma hierarquia de veículos limpa com precificação polimórfica e como o encapsulamento protege a integridade dos dados de aluguel durante todo o fluxo de trabalho.

Experimente você mesmo

<?php

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

// Ler entradas
$fleetJson = trim(fgets(STDIN));
$customerJson = trim(fgets(STDIN));
$operationsJson = trim(fgets(STDIN));

// Analisar dados JSON
$fleetData = (array)json_decode($fleetJson, true);
$customerData = (array)json_decode($customerJson, true);
$operations = (array)json_decode($operationsJson, true);

// TODO: Criar instância de RentalService

// TODO: Adicionar todos os veículos à frota com base no tipo:
// - "car" -> new Car(plate, brand, rate)
// - "motorcycle" -> new Motorcycle(plate, brand, rate)
// - "van" -> new Van(plate, brand, rate, mileage_rate)

// TODO: Criar instância de Customer a partir de customerData

// TODO: Criar array para rastrear aluguéis ativos por placa
$activeRentals = [];

// TODO: Processar cada operação e imprimir resultados:
// - "available": Imprimir "Available vehicles: [count]"
// - "rent": Alugar veículo, armazenar Rental se for bem-sucedido, imprimir resultado
// - "complete": Concluir o aluguel, imprimir resultado
// - "maintenance": Definir manutenção, imprimir resultado
// - "status": Imprimir "[plate]: [status]"
// - "customer_stats": Imprimir "[name]: [count] rentals, $[total] spent"

foreach ($operations as $op) {
    $operation = (array)$op;
    $opType = $operation['op'];
    
    // TODO: Lidar com cada tipo de operação
    switch ($opType) {
        case 'available':
            // TODO: Imprimir contagem de veículos disponíveis
            break;
        case 'rent':
            // TODO: Alugar veículo e imprimir resultado
            break;
        case 'complete':
            // TODO: Concluir aluguel e imprimir resultado
            break;
        case 'maintenance':
            // TODO: Definir manutenção e imprimir resultado
            break;
        case 'status':
            // TODO: Imprimir status do veículo
            break;
        case 'customer_stats':
            // TODO: Imprimir estatísticas do cliente
            break;
    }
}

?>

Todas as lições de Programação Orientada a Objetos