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

C# 介面與抽象類別深度比較:核心差異、適用場景與設計原則

     編輯:關於C#

核心定義

特性介面抽象類別
關鍵字interfaceabstract class
本質契約/規範/能力不完整的基底實作/共享狀態
繼承關係實作 (implements)繼承 (extends)
多重實作/繼承支援多重實作單一繼承
成員實作C# 8.0 前:不可有實作
C# 8.0+:可有預設實作
可有完整實作、虛擬方法、抽象方法
存取修飾詞隱含 public,不可標註可用 public/protected/private/internal
欄位不可有實例欄位(可有靜態常數)可有實例欄位、屬性、事件
建構函式不可有可有 (供衍生類別呼叫)
實例化不可直接實例化不可直接實例化

介面特性詳解

  • 解耦合:定義「能做什麼」,不關心「怎麼做」。如 IFly 可被鳥、飛機、超人實作
  • 多型基石:讓無關類別共享同一介面型別,支援依賴倒置
  • 多重實作一個類別可實作多個介面:class Duck : IFly, ISwim, IQuack
  • 介面繼承介面interface IAnimal : IEat, ISleep
  • 顯式實作void IFly.Fly() { ... } 僅能透過介面參考呼叫,成員為 private
  • 抽象類別實作介面可將介面成員標記為 abstract 延遲實作

抽象類別特性詳解

  • 代碼重用:提供共通實作、欄位、屬性、輔助方法
  • 強制契約:abstract 方法強制衍生類別實作
  • 版本演進:新增非抽象虛擬成員不破壞現有衍生類別(介面新增成員需 C# 8.0 預設實作)
  • 狀態管理:可封裝共享狀態(如資料庫連線、快取、設定)

經典範例


// 介面:定義能力
public interface IFly
{
    void Fly();
    int MaxAltitude { get; }
}

// 抽象類別:共享飛行邏輯與狀態
public abstract class FlyingObject : IFly
{
    protected int _fuel;
    public int Fuel => _fuel;
    
    public abstract int MaxAltitude { get; }
    
    public void Fly()
    {
        if (_fuel <= 0) throw new InvalidOperationException("燃料耗盡");
        Console.WriteLine($"飛行中... 剩餘燃料 {_fuel}");
        _fuel -= 10;
    }
    
    protected virtual void Refuel(int amount) => _fuel += amount;
}

// 具體類別
public class Airplane : FlyingObject
{
    public override int MaxAltitude => 12000;
    public Airplane() => _fuel = 1000;
}

public class Bird : FlyingObject
{
    public override int MaxAltitude => 500;
    public Bird() => _fuel = 50;
    protected override void Refuel(int amount) 
    {
        Console.WriteLine("鳥類覓食補充能量");
        base.Refuel(amount);
    }
}

// 另一個介面
public interface ISwim { void Swim(); }

// 多重實作
public class Duck : FlyingObject, ISwim
{
    public override int MaxAltitude => 100;
    public void Swim() => Console.WriteLine("鴨子游泳");
    public Duck() => _fuel = 30;
}

選擇決策樹

  1. 是否需要共享程式碼/狀態?→ 是 → 抽象類別
  2. 是否需要多重繼承?→ 是 → 介面
  3. 是否定義跨領域的能力/契約?→ 是 → 介面
  4. 是否需要版本演進相容性(新增成員不破壞衍生類)?→ 抽象類別較優(或 C# 8.0+ 介面預設實作)
  5. 是否為值型別(struct)?→ 只能實作介面

C# 8.0+ 介面新功能


public interface ILogger
{
    void Log(string message); // 必須實作
    
    // 預設實作:衍生類別可選擇覆寫
    void LogInfo(string message) => Log($"[INFO] {message}");
    void LogError(string message) => Log($"[ERROR] {message}");
    
    // 靜態成員(不屬於介面契約)
    static ILogger CreateConsoleLogger() => new ConsoleLogger();
    
    // 私有輔助方法
    private string Format(string level, string msg) => $"[{level}] {msg}";
}

最佳實踐

  1. 預設用介面定義契約,配合依賴注入實現鬆耦合
  2. 需要共享實作/狀態時引入抽象基底類別
  3. 組合優於繼承:介面 + 組合 通常優於深層繼承樹
  4. 介面隔離原則 (ISP):介面要小而專一,避免「胖介面」
  5. 命名慣例:介面加 I 前綴(IRepository),抽象類別可加 Base/Abstract 後綴

理解介面與抽象類別的本質差異,是設計彈性、可維護、可測試物件導向系統的關鍵能力。

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