首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

C# 實戰:基於繼承、多態與簡單工廠的汽車租賃管理系統

     編輯:關於C語言

專案背景與設計目標

本專案為一個 Windows Forms 形式的汽車租賃演示系統,旨在通過一個完整的小型業務場景,串聯 繼承、多態、集合操作、簡單工廠模式 等核心 OOP 與設計模式知識點。系統包含三大功能模塊:

  • 車輛入庫:新增轎車/卡車,自動判斷類型實例化對象
  • 租車業務:從可用車輛池移至租出池,記錄租戶信息
  • 還車結算:根據租賃天數多態計算費用,歸還車輛至可用池

領域模型設計

類圖結構

Vehicle (abstract)
├── LicenseNo : string      // 車牌號(唯一鍵)
├── Name : string           // 車型名稱
├── Color : string          // 顏色
├── RentDate : int          // 租賃起始日(簡化為整數)
├── DailyRent : double      // 日租金
├── ReturnDate : int        // 租賃天數
├── GetNum() : double       // 抽象方法:計算總租金
│
├── Car : Vehicle           // 轎車,無額外屬性
│   └── GetNum() = DailyRent * ReturnDate
│
└── Truck : Vehicle         // 卡車
    ├── Load : int          // 載重量(噸)
    └── GetNum() = DailyRent * ReturnDate  // 邏輯同轎車,預留擴展

代碼實現:基類與子類

// 抽象基類
public abstract class Vehicle
{
    public string LicenseNo { get; set; }
    public string Name { get; set; }
    public string Color { get; set; }
    public int RentDate { get; set; }
    public double DailyRent { get; set; }
    public int ReturnDate { get; set; }

    protected Vehicle() { }
    public Vehicle(string licenseNo, string name, string color, int rentDate, double dailyRent)
    {
        LicenseNo = licenseNo; Name = name; Color = color;
        RentDate = rentDate; DailyRent = dailyRent;
    }

    public abstract double GetNum(); // 多態計算租金
}

// 轎車
public class Car : Vehicle
{
    public Car() { }
    public Car(string licenseNo, string name, string color, int rentDate, double dailyRent)
        : base(licenseNo, name, color, rentDate, dailyRent) { }

    public override double GetNum() => DailyRent * ReturnDate;
}

// 卡車
public class Truck : Vehicle
{
    public int Load { get; set; }
    public Truck() { }
    public Truck(string licenseNo, string name, string color, int rentDate, double dailyRent, int load)
        : base(licenseNo, name, color, rentDate, dailyRent) => Load = load;

    public override double GetNum() => DailyRent * ReturnDate; // 可擴展:如按載重分級計費
}

簡單工廠:VehicleFactory

public static class VehicleFactory
{
    public static Vehicle Create(string licenseNo, string name, string color,
                                 int rentDate, double dailyRent, int load, string type)
    {
        return type switch
        {
            "卡車" => new Truck(licenseNo, name, color, rentDate, dailyRent, load),
            "轎車" => new Car(licenseNo, name, color, rentDate, dailyRent),
            _ => throw new ArgumentException("未知車輛類型")
        };
    }
}

設計意圖:將「根據類型創建對象」的邏輯集中封裝,UI 層無需直接 new 具體類,降低耦合,便於後續擴展(如新增「客車」、「新能源車」只需修改工廠)。

主窗體核心邏輯

數據結構:雙字典驅動狀態流轉

// 可租車輛池:Key=車牌號,Value=Vehicle 對象
private readonly Dictionary<string, Vehicle> _available = new();
// 已租車輛池
private readonly Dictionary<string, Vehicle> _rented = new();

租車 = _available.Remove(key) + _rented.Add(key, vehicle);
還車 = _rented.Remove(key) + _available.Add(key, vehicle)。
雙字典交互清晰體現「狀態機」思想,避免在單一集合中維護狀態標記。

通用列表刷新方法

private void RefreshList(Dictionary<string, Vehicle> source, ListView target)
{
    target.Items.Clear();
    foreach (var v in source.Values)
    {
        var item = new ListViewItem(v.LicenseNo);
        item.SubItems.AddRange(new[] { v.Name, v.Color, v.RentDate.ToString(), v.DailyRent.ToString() });
        if (v is Truck t) item.SubItems.Add(t.Load.ToString());
        target.Items.Add(item);
    }
}

利用 is 模式匹配區分車型,動態決定是否顯示「載重」列,展現多態在 UI 渲染中的應用。

租車按鈕事件

private void btnRent_Click(object sender, EventArgs e)
{
    if (lvAvailable.SelectedItems.Count == 0) { ShowMsg("請選擇一輛車"); return; }
    if (string.IsNullOrWhiteSpace(txtRenter.Text)) { ShowMsg("請輸入租戶姓名"); return; }

    string licenseNo = lvAvailable.SelectedItems[0].Text;
    var vehicle = _available[licenseNo];
    vehicle.RentUser = txtRenter.Text; // 假設 Vehicle 增加 RentUser 屬性

    _rented.Add(licenseNo, vehicle);
    _available.Remove(licenseNo);
    RefreshList(_available, lvAvailable);
    ShowMsg("租車成功");
}

還車結算按鈕事件(多態計費核心)

private void btnReturn_Click(object sender, EventArgs e)
{
    if (string.IsNullOrWhiteSpace(txtDays.Text)) { ShowMsg("請輸入租賃天數"); return; }
    if (lvRented.SelectedItems.Count == 0) { ShowMsg("請選擇要還車的記錄"); return; }

    string licenseNo = lvRented.SelectedItems[0].Text;
    var vehicle = _rented[licenseNo];
    vehicle.ReturnDate = int.Parse(txtDays.Text);

    double fee = vehicle.GetNum(); // 多態調用:Car/Truck 各自實現
    if (MessageBox.Show($"應收費用:{fee} 元,確定結算?", "確認", MessageBoxButtons.OKCancel, MessageBoxIcon.Question) != DialogResult.OK)
        return;

    _available.Add(licenseNo, vehicle);
    _rented.Remove(licenseNo);
    RefreshList(_rented, lvRented);
    ShowMsg("還車成功");
}

亮點:vehicle.GetNum() 在運行時根據實際對象類型(Car/Truck)動態分發,無需在 UI 層寫 if/else 判斷,完美詮釋「面向接口編程、多態消除條件分支」。

入庫按鈕事件(工廠模式應用)

private void btnStockIn_Click(object sender, EventArgs e)
{
    if (!ValidateInput()) { ShowMsg("請完善所有信息"); return; }
    if (_available.ContainsKey(txtLicenseNo.Text)) { ShowMsg("車牌號已存在"); return; }

    string type = rdoTruck.Checked ? "卡車" : "轎車";
    int load = rdoTruck.Checked ? int.Parse(txtLoad.Text) : 0; // 軎車載重無效

    var vehicle = VehicleFactory.Create(
        txtLicenseNo.Text, txtName.Text, cmbColor.Text,
        int.Parse(txtRentDate.Text), double.Parse(txtDailyRent.Text),
        load, type);

    _available.Add(vehicle.LicenseNo, vehicle);
    RefreshList(_available, lvAvailable);
    ClearInputFields();
    ShowMsg("入庫成功");
}

單選按鈕 CheckedChanged 事件動態啟用/禁用「載重」輸入框,體現 UI 與領域模型的聯動。

界面佈局與關鍵控件

  • TabControl:三頁籤分離「可租車輛」、「已租車輛」、「新車入庫」
  • ListView (Details 視圖):多列顯示車輛屬性,配合 FullRowSelect = true 整行選中
  • RadioButton 組:轎車/卡車互斥選擇,控制載重輸入框可用狀態
  • TextBox / ComboBox / NumericUpDown:輸入車牌、名稱、顏色、租賃日、日租金、載重等

擴展建議與最佳實踐

方向具體做法
持久化引入 SQLite / SQL Server,將雙字典改為 Repository 模式,支持斷點續租
並發安全多窗口/多線程場景下,對字典操作加 lock 或改用 ConcurrentDictionary
計費策略模式將 GetNum() 抽離為 IRentCalculator 接口,支持「會員折扣」「節假日漲價」「超時罰款」等組合策略
異步化 UI數據庫讀寫、導出報表等耗時操作改為 async/await,防止界面凍結
單元測試對 VehicleFactory、計費邏輯、狀態流轉編寫 xUnit 測試,保證核心業務穩健

總結

本專案通過一個「麻雀雖小、五臟俱全」的汽車租賃系統,將 繼承建立領域層次、多態消除條件判斷、集合實現狀態流轉、簡單工廠解耦創建邏輯 串聯起來。代碼結構清晰、職責單一,既可作為初學者理解 OOP 與設計模式落地的範例,也可作為小型管理系統的起步框架直接擴展。掌握「雙字典驅動狀態機」與「工廠+多態」組合拳,將讓你在面對更複雜的業務建模時游刃有餘。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved