Menu
Coddy logo textTech

차량 대여 서비스

Coddy PHP 여정의 객체 지향 프로그래밍 섹션에 포함된 레슨 — 91개 중 91번째.

challenge icon

챌린지

쉬움

차량 함대를 관리하고, 고객 대여를 추적하며, 차량 유형에 따라 요금을 계산하는 차량 대여 서비스(Vehicle Rental Service) 시스템을 구축해 보겠습니다. 이 종합적인 챌린지는 상속, 인터페이스, 캡슐화 및 상태(State) 패턴을 결합하여 현실적인 대여 비즈니스 애플리케이션을 만듭니다.

코드는 다음 7개의 파일로 구성됩니다.

  • VehicleState.php — 차량이 가질 수 있는 다양한 상태를 나타내는 VehicleState 인터페이스를 정의합니다. getStatus(): stringcanRent(): bool 두 가지 메서드를 포함하세요. 그런 다음 이 인터페이스를 구현하는 세 개의 클래스를 만듭니다.
    • AvailableState"Available"true를 반환합니다.
    • RentedState"Rented"false를 반환합니다.
    • MaintenanceState"Maintenance"false를 반환합니다.
  • Vehicle.php — VehicleState 파일을 포함합니다. licensePlate (string, public readonly), brand (string, public readonly), dailyRate (float, protected)에 대해 생성자 프로모션(constructor promotion)을 사용하는 추상 Vehicle 클래스를 만듭니다. 현재 상태를 private 속성에 저장하며, 기본값은 AvailableState입니다. 다음을 구현하세요:
    • getState(): VehicleState — 현재 상태를 반환합니다.
    • setState(VehicleState $state): void — 상태를 변경합니다.
    • getStatus(): string — 상태 객체의 getStatus()에 위임합니다.
    • canRent(): bool — 상태 객체의 canRent()에 위임합니다.
    • abstract calculateCost(int $days): float — 각 차량 유형마다 다르게 계산됩니다.
    • getType(): stringstatic::class를 사용하여 클래스 이름을 반환합니다.
  • Vehicles.php — Vehicle 파일을 포함합니다. 세 개의 구체적인 차량 클래스를 만듭니다.
    • Car — Vehicle을 상속받습니다. calculateCost()dailyRate * days를 반환합니다.
    • Motorcycle — Vehicle을 상속받습니다. calculateCost()dailyRate * days * 0.8 (20% 할인)을 반환합니다.
    • Van — 추가적인 $mileageRate (float) 매개변수를 가진 Vehicle을 상속받습니다. calculateCost(int $days, int $miles = 0)(dailyRate * days) + (mileageRate * miles)를 반환합니다.
  • Customer.phpid (int, public readonly) 및 name (string, public readonly)에 대해 생성자 프로모션을 사용하는 Customer 클래스를 만듭니다. 대여 내역을 private 배열로 추적합니다. 다음을 구현하세요:
    • 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()에 miles를 전달하고, 그렇지 않으면 days만 전달합니다.
    • complete(): string — 총액을 계산하고, 고객의 내역에 추가하며, 차량을 AvailableState로 설정하고, "Rental completed: $[total]" (소수점 2자리)을 반환합니다.
  • RentalService.php — Rental 및 Vehicles 파일을 포함합니다. 차량 함대를 관리하는 RentalService 클래스를 만듭니다. 차량을 번호판(license plate)을 인덱스로 하는 private 배열에 저장합니다. 다음을 구현하세요:
    • addVehicle(Vehicle $vehicle): void — 함대에 추가합니다.
    • findVehicle(string $plate): ?Vehicle — 차량을 반환하거나 없으면 null을 반환합니다.
    • getAvailableVehicles(): arraycanRent()가 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"}]

    대여 서비스를 생성하고, 모든 차량을 함대에 추가하며, 고객을 생성합니다. 번호판별로 활성 대여(active rentals)를 추적합니다. 각 작업을 처리하세요:

    • "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자리)를 출력합니다.

    각 결과는 새 줄에 출력합니다.

이 시스템은 상태 패턴이 복잡한 조건문 없이 차량 가용성을 어떻게 우아하게 처리하는지, 상속이 다형성 요금 체계를 갖춘 깔끔한 차량 계층 구조를 어떻게 만드는지, 그리고 캡슐화가 워크플로 전반에서 대여 데이터의 무결성을 어떻게 보호하는지 보여줍니다.

직접 해보기

<?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: 유형에 따라 모든 차량을 플릿(fleet)에 추가:
// - "car" -> new Car(plate, brand, rate)
// - "motorcycle" -> new Motorcycle(plate, brand, rate)
// - "van" -> new Van(plate, brand, rate, mileage_rate)

// TODO: customerData로부터 Customer 인스턴스 생성

// 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;
    }
}

?>

객체 지향 프로그래밍의 모든 레슨