Menu
Coddy logo textTech

Сервис аренды транспорта

Часть раздела Объектно-ориентированное программирование путешествия по C# на Coddy — урок 70 из 70.

challenge icon

Задание

Легко

Давайте создадим сервис по прокату автомобилей, который объединяет в себе наследование, интерфейсы и паттерн Стратегия (Strategy)! Вы создадите систему, в которой различные типы транспортных средств можно арендовать, используя гибкие стратегии ценообразования, что продемонстрирует, как ООП позволяет создавать поддерживаемую и расширяемую бизнес-логику.

Вы организуете свой код в шести файлах:

  • Vehicle.cs: Создайте иерархию транспортных средств в пространстве имен Rental.Models. Базовый класс Vehicle должен иметь свойства только для чтения LicensePlate и Brand, DailyRate (decimal) и свойство IsAvailable с приватным сеттером, управляемым через методы MarkAsRented() и MarkAsReturned(). Затем создайте три производных класса: Car со свойством Seats, Motorcycle со свойством EngineCC и Truck со свойством CargoCapacity (decimal). Каждый производный класс должен вызывать конструктор базового класса и устанавливать свое уникальное свойство.
  • IPricingStrategy.cs: Определите интерфейс IPricingStrategy в пространстве имен Rental.Pricing с единственным методом CalculatePrice(Vehicle vehicle, int days), который возвращает decimal.
  • PricingStrategies.cs: Реализуйте две стратегии ценообразования в пространстве имен Rental.Pricing. StandardPricing просто умножает ежедневную ставку транспортного средства на количество дней. WeekendDiscountPricing применяет скидку 10% (умножает на 0.9), если аренда длится 2 или более дней, в противном случае использует стандартный расчет.
  • RentalRecord.cs: Создайте класс Rental в пространстве имен Rental.Models для отслеживания аренды. Он должен иметь свойства только для чтения CustomerName (string), Vehicle (Vehicle), Days (int) и TotalPrice (decimal), все они устанавливаются через конструктор.
  • RentalService.cs: Создайте класс RentalService в пространстве имен Rental.Services, который управляет автопарком и обрабатывает аренду. Он получает IPricingStrategy через свой конструктор (внедрение зависимостей). Реализуйте:
    • AddVehicle(Vehicle vehicle) — добавляет транспортное средство в автопарк
    • RentVehicle(string customerName, string licensePlate, int days) — возвращает объект Rental, если транспортное средство существует и доступно, в противном случае возвращает null. Не забудьте пометить транспортное средство как арендованное и рассчитать цену, используя внедренную стратегию.
    • ReturnVehicle(string licensePlate) — помечает транспортное средство как доступное, возвращает true в случае успеха
    • GetAvailableVehicles() — возвращает список всех доступных транспортных средств
  • Program.cs: Объедините все вместе, создавая транспортные средства, настраивая сервис со стратегией ценообразования и обрабатывая операции аренды на основе входных данных.

Вы получите следующие входные данные:

  • Стратегия ценообразования (standard или weekend)
  • Количество добавляемых транспортных средств
  • Для каждого транспортного средства: тип (car, motorcycle или truck), номерной знак, марка, ежедневная ставка и значение, специфичное для типа (количество мест, объем двигателя или грузоподъемность)
  • Количество выполняемых операций
  • Для каждой операции: действие, за которым следуют соответствующие данные

Форматы операций:

rent
{customerName}
{licensePlate}
{days}

return
{licensePlate}

available

Форматы вывода:

  • Успешная аренда: Rented: {Brand} ({LicensePlate}) to {CustomerName} for {Days} days - Total: {TotalPrice}
  • Ошибка аренды: Rental failed: {licensePlate}
  • Успешный возврат: Returned: {licensePlate}
  • Ошибка возврата: Return failed: {licensePlate}
  • Доступные: Выведите каждое доступное транспортное средство в формате {Type}: {Brand} ({LicensePlate}) - {DailyRate}/day, где Type — это "Car", "Motorcycle" или "Truck"

Например, если входные данные следующие:

weekend
3
car
ABC-123
Toyota
50
5
motorcycle
XYZ-789
Honda
30
600
truck
TRK-001
Ford
80
2000
5
available
rent
Alice
ABC-123
3
rent
Bob
ABC-123
2
available
return
ABC-123

Вывод должен быть таким:

Car: Toyota (ABC-123) - 50/day
Motorcycle: Honda (XYZ-789) - 30/day
Truck: Ford (TRK-001) - 80/day
Rented: Toyota (ABC-123) to Alice for 3 days - Total: 135
Rental failed: ABC-123
Motorcycle: Honda (XYZ-789) - 30/day
Truck: Ford (TRK-001) - 80/day
Returned: ABC-123

Обратите внимание, как стратегия ценообразования внедряется в сервис — вы могли бы легко заменить StandardPricing на WeekendDiscountPricing, вообще не меняя код RentalService. В этом и заключается сила паттерна Стратегия в сочетании с внедрением зависимостей!

Попробуйте сами

using System;
using System.Collections.Generic;
using Rental.Models;
using Rental.Pricing;
using Rental.Services;

class Program
{
    public static void Main(string[] args)
    {
        // Чтение типа стратегии ценообразования
        string strategyType = Console.ReadLine();
        
        // TODO: Создать соответствующую стратегию ценообразования на основе ввода
        // "standard" -> StandardPricing
        // "weekend" -> WeekendDiscountPricing
        IPricingStrategy strategy = null; // TODO: Инициализировать на основе strategyType
        
        // TODO: Создать RentalService со стратегией ценообразования
        
        // Чтение количества транспортных средств
        int vehicleCount = Convert.ToInt32(Console.ReadLine());
        
        // TODO: Прочитать и добавить каждое транспортное средство в сервис
        // Для каждого транспортного средства прочитать:
        // - тип (car, motorcycle, truck)
        // - номерной знак
        // - марку
        // - дневную ставку
        // - специфическое для типа значение (количество мест, объем двигателя или грузоподъемность)
        
        // Чтение количества операций
        int operationCount = Convert.ToInt32(Console.ReadLine());
        
        // TODO: Обработать каждую операцию
        // Операции: rent, return, available
        // 
        // Для "rent":
        //   Прочитать customerName, licensePlate, days
        //   Вывод: "Rented: {Brand} ({LicensePlate}) to {CustomerName} for {Days} days - Total: {TotalPrice}"
        //   Или: "Rental failed: {licensePlate}"
        //
        // Для "return":
        //   Прочитать licensePlate
        //   Вывод: "Returned: {licensePlate}" или "Return failed: {licensePlate}"
        //
        // Для "available":
        //   Вывести каждое доступное транспортное средство в формате:
        //   "{Type}: {Brand} ({LicensePlate}) - {DailyRate}/day"
    }
}

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