Сервис аренды транспорта
Часть раздела Объектно-ориентированное программирование путешествия по C# на Coddy — урок 70 из 70.
Задание
ЛегкоДавайте создадим сервис по прокату автомобилей, который объединяет в себе наследование, интерфейсы и паттерн Стратегия (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"
}
}
Все уроки раздела Объектно-ориентированное программирование
1Основы ООП
Внешние файлыПространства имен и директивыВведение в классы и объектыКлючевое слово 'this'Методы и параметрыПоля и свойстваКонструкторыИнициализаторы объектовИтоги — Простой калькулятор4Наследование
Основы синтаксиса наследования (:)Ключевое слово 'base'Ключевые слова Virtual и OverrideЗапечатанные классыБазовый класс 'object'Итоги — Иерархия сотрудников7Продвинутые возможности
Перегрузка операторовИндексаторы (this[])Переопределение ToString()Методы расширенияПовторение — Пользовательский список10Паттерны проектирования. Часть 1
Введение в паттерны проектированияПотокобезопасный SingletonПаттерн FactoryПаттерн Observer (События)Паттерн Strategy13Финальные испытания
Платформа для онлайн-обученияКомпонент игрового персонажаСервис аренды транспорта2Свойства и статические члены
Автоматически реализуемые свойстваСвойства только для чтения и записиСтатические поля и методыСтатические классыЧлены в виде выражений5Полиморфизм и интерфейсы
Полиморфизм: компиляция vs выполнениеИнтерфейс vs абстрактный классМножественные интерфейсыЯвные интерфейсыUpcasting и DowncastingИтоги: Калькулятор фигур8Продвинутые концепции ООП
Композиция вместо наследованияGenerics (классы и методы)Делегаты и событияАтрибуты и рефлексияIDisposable и оператор usingОсновы Dependency Injection11Паттерны проектирования. Часть 2
Паттерн КомандаПаттерн АдаптерПаттерн ДекораторПаттерн Шаблонный методПаттерн СостояниеПаттерн Компоновщик3Архитектура классов
Экземплярные и статические данныеКлючевые слова 'readonly' и 'const'Опорные поляПовторение — Менеджер банковских счетов6Инкапсуляция
Модификаторы доступаСвойства для инкапсуляцииРеализация скрытия данныхПаттерны неизменяемостиИтоги — Записи студентов9Переменное количество аргументов
Ключевое слово 'params'Необязательные параметрыИменованные аргументыПерегрузка методов