IRONSOFTWAREHOME

理解C#中的面向物件程式設計

Understanding C# OOP

Tim Corey

49m 41s

繼承和介面是物件導向程式設計 (OOP) 的重要組成部分。 Tim Corey在他的影片"繼承與介面在 C# 中的比較:物件導向程式設計"中,詳細解釋了何時使用繼承以及何時選擇介面。

這篇文章是Tim Corey影片的綜合指南。 它分解了影片中提供的關鍵概念、範例和程式碼解釋,強調了繼承與介面的差異以及何時使用各自的情況。

介紹

Tim在 (0:00) 開始強調區分繼承與介面的重要性。 他重申理解何時使用每個概念以獲得最佳效果的重要性。 他的目標是通過範例展示這一點,首先從單一繼承的錯誤使用開始,然後進行修正。

建立專案

在 (1:08),Tim使用 .NET 5 建立了一個簡單的主控台應用程式。他將專案命名為 "OODemoApp",並解釋其主要目的是演示概念而非建立適合生產的程式碼。

理解繼承

Tim在 (1:55) 探討了繼承的基礎。 他將繼承定義為一種機制,基類的屬性和方法由衍生類繼承。 他強調,繼承不應僅用於程式碼重用和共享,而應用於建立邏輯上的 "是-一" 關係。

關鍵點:

  • 是-一 關係:確保衍生類是基類的一種型別。
  • 共通邏輯:繼承的類別應共享共通邏輯,而不僅僅是屬性或方法簽名。

範例類別:租車

Tim在 (7:52) 建立了一個 RentalCar 類別,以說明繼承的基本概念。 此類別代表佛羅里達州邁阿密租車機構中的一輛出租車。

public class RentalCar
{
    public int RentalId { get; set; }
    public string CurrentRenter { get; set; }
    public decimal PricePerDay { get; set; }
    public int NumberOfPassengers { get; set; }

    public void StartEngine()
    {
        Console.WriteLine("Turn key to ignition setting");
        Console.WriteLine("Turn key to on");
    }

    public void StopEngine()
    {
        Console.WriteLine("Turn key to off");
    }
}

展示不正確繼承的陷阱

Tim在 (10:15) 解釋了不當使用繼承可能引發的問題。 他強調,如果錯誤運用繼承,可能導致難以管理和擴展的程式碼。 他建議不要僅僅為了分享程式碼而使用繼承。

為汽車和卡車型別新增列舉

Tim在 (10:45) 新增了一個汽車型別的列舉。他建立了一個名為 Enums.cs 的新類別文件,以便所有列舉都集中在一處。 此列舉將幫助區分不同的汽車樣式。

// Enums.cs
public enum CarType
{
    Hatchback,
    Sedan,
    Compact
}

然後,他在 RentalCar 類中新增了一個屬性,以指明汽車型別。

public class RentalCar : RentalVehicle
{
    public CarType Style { get; set; }
    // Other properties and methods
}

擴展以包含卡車

如 Tim 在 (12:27) 解釋的那樣,租車公司決定將卡車納入其車隊,這帶來了新的需求。 他建立了一個從父類 RentalVehicle 繼承的 RentalTruck 類。

public class RentalTruck : RentalVehicle
{
    public TruckType Style { get; set; }
    // Other properties and methods
}

然後,他定義了一個新的卡車型別的列舉。

// Enums.cs
public enum TruckType
{
    ShortBed,
    LongBed
}

處理不同的屬性型別

Tim在 (15:28) 強調,僅僅因為兩個屬性有相同的名稱並不意味著它們是相同的。 他用 Style 屬性說明了這一點,這對汽車來說可能意味著不同的列舉(CarType 對汽車而言,而對卡車來說則是 TruckType)。

引入船隻到車隊

租車公司擴展其車隊以包括船隻。 Tim演示如何通過建立一個 RentalBoat 類進行處理。 最初,這似乎是可控的,因為船隻可以與汽車和卡車共享一些屬性。

public class RentalBoat : RentalVehicle
{
    // Properties and methods specific to boats
}

處理帆船

引入帆船帶來了挑戰,因為帆船沒有引擎。 Tim在 (19:57) 中說明了在這種情況下繼承的限制。

public class RentalSailboat : RentalVehicle
{
    public override void StartEngine()
    {
        throw new NotImplementedException("I do not have an engine to start");
    }

    public override void StopEngine()
    {
        throw new NotImplementedException("I do not have an engine to stop");
    }
}

用介面解決問題

Tim建議在基類中將 StartEngine 和 StopEngine 方法設為虛擬的,以允許在不使用這些方法的衍生類中重載。

public abstract class RentalVehicle
{
    // Common properties

    public virtual void StartEngine()
    {
        Console.WriteLine("Engine started");
    }

    public virtual void StopEngine()
    {
        Console.WriteLine("Engine stopped");
    }
}

處理不應調用的方法

Tim在 (21:56) 解釋存在於繼承類中的應避免調用的方法的陷阱。 例如,不具備引擎的 RentalSailboat 類,從 RentalVehicle 類繼承了 StartEngine 和 StopEngine 方法。 若誤調用這些方法可能會引發問題,因為這些方法必須拋出例外,以表明它們不適用。

public class RentalSailboat : RentalVehicle
{
    public override void StartEngine()
    {
        throw new NotImplementedException("I do not have an engine to start");
    }

    public override void StopEngine()
    {
        throw new NotImplementedException("I do not have an engine to stop");
    }
}

認識繼承的限制

Tim在 (24:06) 強調繼承若不再符合邏輯,會導致程式碼庫雜亂無章。 例如,帆船不應被視作具備引擎的 RentalVehicle。這顯示了繼承的限制性,以及需要更好的設計方針。

用介面改進設計

為了解決這些問題,Tim 建議使用介面進行更好的設計。 他開始通過建立一個名為 "BetterOODemo" 的新主控台應用程式項目,來示範改進的方法。

定義介面

Tim引入IRental介面以封裝所有租用共享的屬性。

public interface IRental
{
    int RentalId { get; set; }
    string CurrentRenter { get; set; }
    decimal PricePerDay { get; set; }
}

建立陸地交通工具的基類

Tim接著建立了一個陸地交通工具的基類,將交通工具租賃的概念與交通工具本身分開。

public abstract class LandVehicle
{
    public int NumberOfPassengers { get; set; }

    public virtual void StartEngine()
    {
        Console.WriteLine("Engine started");
    }

    public virtual void StopEngine()
    {
        Console.WriteLine("Engine stopped");
    }
}

將基礎交通工具類重新命名為 LandVehicle,Tim 確保只有合適的車輛繼承與引擎相關的方法。

實現汽車和卡車類

Tim建立汽車和卡車類,這些類繼承自 LandVehicle 並實現 IRental 介面。

public class Car : LandVehicle, IRental
{
    public int RentalId { get; set; }
    public string CurrentRenter { get; set; }
    public decimal PricePerDay { get; set; }
    public CarType Style { get; set; }
}

public class Truck : LandVehicle, IRental
{
    public int RentalId { get; set; }
    public string CurrentRenter { get; set; }
    public decimal PricePerDay { get; set; }
    public TruckType Style { get; set; }
}

此設計保持了關注點的清晰分離,確保每個類僅獲得與自身型別相關的屬性和方法。

避免程式碼重複

Tim在 (31:41) 談到了避免不必要程式碼重複的重要性。 他解釋說,儘管 IRental 介面要求在多個類中使用相同的屬性,但這不被視為違反 DRY(Don't Repeat Yourself)原則,因為未重複任何邏輯 - 僅是屬性聲明。

實現租賃帆船類

Tim在 (35:09) 解釋如何通過實現 IRental 介面而非繼承 LandVehicle 單獨處理 RentalSailboat 類。 這種方法有助於避免不當繼承相關的問題。

public class Sailboat : IRental
{
    public int RentalId { get; set; }
    public string CurrentRenter { get; set; }
    public decimal PricePerDay { get; set; }

    // Additional properties and methods specific to sailboats
}

管理不同的租賃

Tim設置了一個列表來管理不同型別的租賃,利用 IRental 介面來儲存各種租賃型別,包括卡車、帆船和汽車。

List<IRental> rentals = new List<IRental>
{
    new Truck { CurrentRenter = "Truck Renter" },
    new Sailboat { CurrentRenter = "Sailboat Renter" },
    new Car { CurrentRenter = "Car Renter" }
};

此設計允許迴圈遍歷租賃並存取共通屬性如 CurrentRenter, PricePerDayRentalId

foreach (var rental in rentals)
{
    Console.WriteLine($"Renter: {rental.CurrentRenter}, Price Per Day: {rental.PricePerDay}");
}

型別專屬轉型

要存取不同租賃型別的特定屬性和方法,Tim演示如何使用 is 關鍵字來檢查並將物件轉型為各自的型別。

foreach (var rental in rentals)
{
    if (rental is Truck truck)
    {
        Console.WriteLine($"Truck Style: {truck.Style}, Passengers: {truck.NumberOfPassengers}");
    }
    else if (rental is Sailboat sailboat)
    {
        // Access sailboat-specific properties
    }
    else if (rental is Car car)
    {
        // Access car-specific properties
    }
}

介面的靈活性

Tim強調使用介面提供後續變更的靈活性。 例如,新增坦克或電視等新的租賃型別,不會擾亂現有結構。

避免濫用繼承

Tim建議不要過度使用繼承來分享程式碼,因為這可能導致複雜且不靈活的程式碼庫。 反之,他建議利用介面和組合來達成所需結果,而不致將 "是-一" 的關係延伸超出其邏輯範圍。

結論

Tim Corey對OOP中繼承與介面的解釋,提供了建立可維護與靈活的程式碼的明確道路。 通過展示常見陷阱並提供使用介面的精煉設計,他確保開發者可以做出明智的決策來有效地構建程式。

要深入了解這些概念並看它們的實際應用,請欣賞 Tim 的完整影片。 他的頻道是程式設計教學的寶庫。 不要錯過!

Earn More by Sharing What You Love

Do you create content for developers working with .NET, C#, Java, Python, or Node.js? Turn your expertise into extra income!

Let's Stay in Touch!

Join our newsletter, you’ll get exclusive access on article updates. We value your privacy

Key in blue circle

立即免費取得 30 天試用金鑰

Your trial license will be sent to your email address

無任何限制。100% 解鎖。無需信用卡。

OR
bullet_checked無需信用卡或建立帳號無任何限制。100% 解鎖。無需信用卡。
  • Logo Aetna
  • Logo NASA
  • Logo GE
  • Logo Porsche
  • Logo USDA
  • Logo Qatar
Join Millions of Engineers who’ve tried Iron Suite
獲取您的無義務諮詢
填寫以下表格或發送電子郵件至sales@ironsoftware.com
您的詳細資訊將始終保密。
被全球數百萬工程師信任
Iron Software的客戶標誌
立即獲取您的30天試用金鑰
無需信用卡或帳戶建立