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.
Desafio
FácilVamos 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 interfaceVehicleStateque representa os diferentes estados em que um veículo pode estar. Inclua dois métodos:getStatus(): stringecanRent(): bool. Em seguida, crie três classes implementando esta interface:AvailableState— retorna"Available"etrueRentedState— retorna"Rented"efalseMaintenanceState— retorna"Maintenance"efalse
Vehicle.php— Inclua o arquivo VehicleState. Crie uma classe abstrataVehiclecom promoção de construtor paralicensePlate(string, public readonly),brand(string, public readonly) edailyRate(float, protected). Armazene o estado atual em uma propriedade privada, com o valor padrãoAvailableState. Implemente:getState(): VehicleState— retorna o estado atualsetState(VehicleState $state): void— altera o estadogetStatus(): string— delega para ogetStatus()do estadocanRent(): bool— delega para ocanRent()do estadoabstract calculateCost(int $days): float— cada tipo de veículo calcula de forma diferentegetType(): string— retorna o nome da classe usandostatic::class
Vehicles.php— Inclua o arquivo Vehicle. Crie três classes de veículos concretas:Car— estende Vehicle;calculateCost()retornadailyRate * daysMotorcycle— estende Vehicle;calculateCost()retornadailyRate * 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 classeCustomercom promoção de construtor paraid(int, public readonly) ename(string, public readonly). Rastreie o histórico de aluguéis em um array privado. Implemente:addRental(string $vehiclePlate, float $cost): void— adiciona ao históricogetRentalCount(): int— retorna o número de aluguéisgetTotalSpent(): float— retorna a soma de todos os custos de aluguel
Rental.php— Inclua os arquivos Vehicle e Customer. Crie uma classeRentalque vincula um cliente a um veículo. Use promoção de construtor paracustomer(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 paracalculateCost(); caso contrário, passe apenas dayscomplete(): 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 classeRentalServiceque gerencia a frota. Armazene os veículos em um array privado indexado pela placa (license plate). Implemente:addVehicle(Vehicle $vehicle): void— adiciona à frotafindVehicle(string $plate): ?Vehicle— retorna o veículo ou nullgetAvailableVehicles(): array— retorna veículos ondecanRent()é truerentVehicle(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 RentalsetMaintenance(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 desetMaintenance()"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
1Fundamentos de POO
Arquivos ExternosIntrodução à POOClasses vs ObjetosA Palavra-chave $thisMétodosPropriedadesConstrutor (__construct)Destrutor (__destruct)Recapitulação - Calculadora Simples4Herança
Herança BásicaA Palavra-chave parent::Sobrescrita de MétodoA Palavra-chave finalClasses AbstratasRecapitulação - Hierarquia de Funcionários7Encapsulamento
Público, Protegido, PrivadoModificadores de Acesso em DetalhesGetters e SettersOcultação de InformaçãoPromoção de Construtor (8.0)Recapitulação - Sistema de Registro de Alunos10Conceitos Avançados de POO
Composição vs HerançaInjeção de DependênciaClasses AnônimasEnums (PHP 8.1)Fibers (PHP 8.1)Mergulho Profundo em Clonagem de ObjetosGeradores e Iteradores13Padrões de Projeto Parte 2
Padrão CommandPadrão AdapterPadrão DecoratorPadrão Template MethodPadrão StatePadrão CompositePadrão Repository2Namespaces e Autoloading
Introdução a NamespacesA Palavra-chave usePadrão de Autoloading PSR-4Autoloader do ComposerRecapitulação - Projeto Organizado5Interfaces e Contratos
Introdução a InterfacesImplementando InterfacesImplementação de Múltiplas InterfacesInterface vs Classe AbstrataType Hinting com InterfacesRecapitulação - Calculadora de Formas8Métodos Mágicos
Introdução aos Métodos Mágicos__toString e __debugInfo__get, __set, __isset, __unset__call e __callStatic__clone e Clonagem de Objetos__serialize e __unserializeRecapitulação - Coleção Personalizada11Sistema de Tipos e Tratamento de Erros
Declarações de TiposTipos AnuláveisTipos de União e InterseçãoClasses de ExceçãoHierarquia de Exceções PersonalizadasTry, Catch, FinallyRecapitulação - Validador de Formulário14Projeto: Gerenciamento de Biblioteca
Visão Geral do ProjetoClasses Livro e Usuário3Propriedades de Classe
Propriedades de Instância vs EstáticasConstantes em ClassesMétodos e Propriedades EstáticosPropriedades Privadas e ProtegidasPropriedades Readonly (PHP 8.1)Recapitulação - Gerenciador de Conta Bancária6Polimorfismo
Sobrescrita de Métodos RevisitadaPolimorfismo via InterfacesType Hinting e Union TypesLate Static BindingRecapitulação - Processador de Pagamentos9Traits
Introdução a TraitsUsando Múltiplos TraitsResolução de Conflitos de TraitsMétodos Abstratos em TraitsTraits vs Herança12Padrões de Projeto Parte 1
Introdução aos Padrões de ProjetoPadrão SingletonPadrão FactoryPadrão ObserverPadrão Strategy15Desafios Finais
Plataforma de E-LearningSistema BancárioDesenvolvimento de Personagens de JogosServiço de Aluguel de Veículos