2024-11-09 028_抽象類 與 接口類具體解釋

2024-11-09 028_抽象類 與 接口類具體解釋

在 C# 中,抽象類和接口都是用來定義類的行為約束的,但它們的用法和設計目的是不同的。下面我們具體介紹它們各自的特點和使用場景。

抽象類(Abstract Class)

特點

  1. 不完全的類:抽象類是一種「不完整」的類,因為它可能包含抽象方法,這些方法沒有具體的實現。只有繼承該抽象類的子類才能提供具體的實現。
  2. 可以包含成員變量和方法:抽象類可以包含字段(成員變量)、完全實現的方法(有具體實現的普通方法)和抽象方法(沒有實現的,要求子類實現)。
  3. 繼承限制:子類只能繼承自一個抽象類(因為 C# 不支持多重繼承),因此抽象類更適合用來描述一個類的「基礎行為」或「核心功能」。

使用場景

  • 當不同的類具有相似的核心功能且共享一些行為或字段時,應考慮使用抽象類。例如,動物(Animal)可能作為抽象類,因為所有動物可能有一些共同的行為(如 EatSleep)和屬性(如 Age)。
  • 當你需要為一組相關的類提供基本的實現、並確保子類繼承一些具體行為時,可以選擇抽象類。

範例

1
2
3
4
5
6
7
8
9
10
11
12
13
public abstract class Employee
{
public string Name { get; set; }

// 抽象方法,沒有具體實現
public abstract double CalculateSalary();

// 具體方法,有具體實現
public void PrintEmployeeInfo()
{
Console.WriteLine($"Employee Name: {Name}");
}
}

在這個例子中,Employee 類作為抽象類,因為每個員工都有名字和計算薪水的需求,但不同員工的薪水計算方式可能不同。子類需要實現 CalculateSalary() 方法,但可以直接使用 PrintEmployeeInfo() 方法。

接口(Interface)

特點

  1. 僅定義行為約束:接口只包含方法、屬性、事件和索引器的聲明(即簽名),而不包含具體的實現。
  2. 多重實現:一個類可以實現多個接口,因此接口適合用來定義一組不相關但可能互補的功能(如「可存儲的」、「可打印的」等)。
  3. 無字段:接口不能包含成員變量,所有的成員都是純虛擬的。

使用場景

  • 當需要為不同的類定義無關聯的行為,且這些類可能來自不同的繼承鏈時,使用接口。例如,IPrintable 可以是一個接口,用來表示某物是可打印的,不論是文件、照片或電子郵件等。
  • 當你希望可以在不同的類中共享一組行為,但這些類無法共享一個共同的基礎類時,可以使用接口。

範例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public interface ICalculable
{
double Calculate();
}

public class Invoice : ICalculable
{
public double Amount { get; set; }

public double Calculate()
{
return Amount * 0.9; // 假設計算折扣後的金額
}
}

在這個例子中,ICalculable 接口定義了一個通用的 Calculate 方法,而 Invoice 類實現了它。不同的類(如ProductService)也可以實現 ICalculable,以各自的方式計算數據。

抽象類 vs 接口:什麼時候用?

  • 使用抽象類

    • 當類之間具有繼承關係,並且有相似的屬性和方法時。
    • 當需要提供一部分行為的基礎實現而非完全依賴子類時。
  • 使用接口

    • 當不同的類之間不具有明確的繼承關係,但共享某些行為(如「可比較」、「可存儲」)時。
    • 當需要實現多個行為而不能依賴單一的繼承時。

範例:抽象類與接口的配合

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
// 抽象類
public abstract class Employee
{
public string Name { get; set; }
public abstract double CalculateSalary();
}

// 接口
public interface IBonusCalculable
{
double CalculateBonus();
}

// 子類
public class FullTimeEmployee : Employee, IBonusCalculable
{
public override double CalculateSalary()
{
return 5000; // 假設固定薪水
}

public double CalculateBonus()
{
return CalculateSalary() * 0.1; // 假設 10% 獎金
}
}

在這個例子中,Employee 是抽象類,因為不同類型的員工薪水計算方式不同。而 IBonusCalculable 是接口,提供了額外的 CalculateBonus 方法,用於計算獎金,這讓需要的子類能自行實現額外的獎金計算方式。

總結

  • 抽象類適合用於「具有共同基礎行為」的一組類。
  • 接口適合用於「具有不同屬性但共享行為」的一組類。