車両レンタルサービス
CoddyのC#ジャーニー「オブジェクト指向プログラミング」セクションの一部 — レッスン 70/70。
チャレンジ
簡単継承、インターフェース、そして Strategy パターンを組み合わせた車両レンタルサービスを構築しましょう!異なる車両タイプを柔軟な料金戦略でレンタルできるシステムを作成し、OOPがいかに保守可能で拡張性の高いビジネスロジックを可能にするかを実証します。
コードは以下の6つのファイルに分けて構成します:
Vehicle.cs:Rental.Models名前空間に車両の階層構造を作成します。ベースとなるVehicleクラスは、読み取り専用のLicensePlateとBrandプロパティ、DailyRate(decimal)、およびMarkAsRented()とMarkAsReturned()メソッドを通じて制御されるプライベートセッターを持つIsAvailableプロパティを持つ必要があります。次に、3つの派生クラスを作成します:Seatsプロパティを持つCar、EngineCCプロパティを持つMotorcycle、およびCargoCapacity(decimal) プロパティを持つTruckです。各派生クラスはベースクラスのコンストラクタを呼び出し、固有のプロパティを設定する必要があります。IPricingStrategy.cs:Rental.Pricing名前空間にIPricingStrategyインターフェースを定義し、decimal を返す単一のメソッドCalculatePrice(Vehicle vehicle, int days)を持たせます。PricingStrategies.cs:Rental.Pricing名前空間に2つの料金戦略を実装します。StandardPricingは単純に車両の 1日あたりの料金に日数を掛けます。WeekendDiscountPricingは、レンタルが2日以上の場合は10%割引(0.9を掛ける)を適用し、それ以外の場合は標準の計算を使用します。RentalRecord.cs: レンタルを追跡するためにRental.Models名前空間にRentalクラスを作成します。このクラスは、CustomerName(string)、Vehicle(Vehicle)、Days(int)、およびTotalPrice(decimal) の読み取り専用プロパティを持ち、すべてコンストラクタを通じて設定される必要があります。RentalService.cs:Rental.Services名前空間に、フリート(車両群)を管理しレンタル処理を行うRentalServiceクラスを作成します。このクラスはコンストラクタを通じて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)、ナンバープレート、ブランド、1日あたりの料金、およびタイプ固有の値(座席数、排気量、または積載量) - 実行する操作の数
- 各操作について:アクションとそれに続く関連データ
操作の形式:
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.0
Rental failed: ABC-123
Motorcycle: Honda (XYZ-789) - 30/day
Truck: Ford (TRK-001) - 80/day
Returned: ABC-123料金戦略がサービスにどのように注入されているかに注目してください。RentalService のコードを一切変更することなく、StandardPricing を WeekendDiscountPricing に簡単に交換できます。これが、依存性の注入と組み合わせた Strategy パターンの力です!
自分で試してみよう
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: 各車両を読み込み、サービスに追加する
// 各車両について、以下を読み込む:
// - type (car, motorcycle, truck)
// - license plate
// - brand
// - 1日あたりの料金
// - タイプ固有の値 (seats、engineCC、または cargo capacity)
// 操作の数を読み込む
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"
}
}