抽象類是 C# 面向對象編程中的一個重要概念,它介于普通類和接口之間,提供了一種定義部分實現并要求派生類完成其余部分的機制。
一、C# 中的抽象類
抽象類是 C# 面向對象編程中的一個重要概念,它介于普通類和接口之間,提供了一種定義部分實現并要求派生類完成其余部分的機制。
1. 抽象類的基本概念
抽象類是不能被實例化的類,主要用于作為其他類的基類。它通過 abstract
關鍵字聲明:
public abstract class Animal
{// 類成員
}
2. 抽象類的特點
- ?不能被實例化?:不能創建抽象類的對象
- ?可以包含抽象成員?:這些成員必須在派生類中實現
- ?可以包含具體實現?:與接口不同,抽象類可以包含已實現的方法
- ?可以包含字段、屬性、方法、事件等?:功能比接口更全面
- ?支持訪問修飾符?:可以控制成員的訪問級別
3. 抽象成員
抽象類可以包含抽象成員(方法、屬性、索引器或事件):
public abstract class Animal
{// 抽象方法(無實現)public abstract void MakeSound();// 抽象屬性public abstract string Name { get; set; }
}
派生類必須實現所有抽象成員:
public class Dog : Animal
{public override void MakeSound(){Console.WriteLine("Woof!");}private string _name;public override string Name {get { return _name; }set { _name = value; }}
}
4. 抽象類與具體類的比較
特性 | 抽象類 | 具體類 |
---|---|---|
實例化 | 不能 | 能 |
包含抽象成員 | 可以 | 不能 |
包含具體實現 | 可以 | 可以 |
繼承要求 | 必須實現所有抽象成員 | 無特殊要求 |
5. 抽象類與接口的比較
特性 | 抽象類 | 接口 |
---|---|---|
實現 | 部分實現 | 無實現 |
多繼承 | 不支持 | 支持 |
字段 | 可以包含 | 不能包含 |
構造函數 | 可以有 | 不能有 |
訪問修飾符 | 支持 | 默認public |
版本控制 | 添加新成員可能破壞派生類 | 添加新成員會破壞實現 |
6. 何時使用抽象類
- 當多個相關類共享通用功能,但各自又有獨特行為時
- 需要提供一些基礎實現,同時要求派生類實現特定功能時
- 需要包含非公共成員(protected/internal)時
- 需要定義構造函數、析構函數或靜態成員時
7. 抽象類的實際示例
public abstract class Shape
{// 抽象方法 - 必須被派生類實現public abstract double Area();// 具體方法 - 已實現public void Display(){Console.WriteLine($"Area: {Area()}");}// 抽象屬性public abstract string Color { get; set; }
}public class Circle : Shape
{public double Radius { get; set; }public override string Color { get; set; }public override double Area(){return Math.PI * Radius * Radius;}
}public class Rectangle : Shape
{public double Width { get; set; }public double Height { get; set; }public override string Color { get; set; }public override double Area(){return Width * Height;}
}
8. 抽象類的進階用法
8.1 抽象類中的構造函數
public abstract class Vehicle
{protected string _model;protected Vehicle(string model){_model = model;}public abstract void Drive();
}public class Car : Vehicle
{public Car(string model) : base(model) { }public override void Drive(){Console.WriteLine($"Driving {_model}");}
}
8.2 部分實現的模板方法模式
public abstract class DataProcessor
{// 模板方法public void Process(){ReadData();ProcessData();SaveResult();}protected abstract void ReadData();protected abstract void ProcessData();protected virtual void SaveResult(){Console.WriteLine("Default save implementation");}
}
9. 總結
抽象類是 C# 中實現多態和代碼重用的強大工具,它:
- 強制派生類實現特定行為
- 提供共享的基類實現
- 比接口更靈活,可以包含狀態和行為
- 適合構建具有層次結構的類家族
正確使用抽象類可以使代碼更加清晰、可維護,并減少重復代碼。
二、C# 中的接口
接口是 C# 中實現多態和抽象的核心機制之一,它定義了一組相關功能的契約,而不提供具體實現。
1. 接口的基本概念
接口使用 interface
關鍵字聲明:
public interface IAnimal
{void MakeSound();string Name { get; set; }
}
2. 接口的特點
- ?純契約?:只包含成員聲明,不包含實現
- ?多繼承?:一個類可以實現多個接口
- ?隱式公開?:所有成員默認是 public 的
- ?不能包含字段?:只能包含方法、屬性、事件和索引器
- ?不能有構造函數?:因為不能被實例化
- ?不能包含靜態成員?(C# 8.0 前)
3. 接口成員的實現
類通過 :
符號實現接口,并提供具體實現:
public class Dog : IAnimal
{private string _name;public void MakeSound(){Console.WriteLine("Woof!");}public string Name {get { return _name; }set { _name = value; }}
}
4. 顯式接口實現
當多個接口有同名成員時,可使用顯式實現:
public class Animal : IAnimal, IDisposable
{void IAnimal.MakeSound(){Console.WriteLine("Animal sound");}void IDisposable.Dispose(){Console.WriteLine("Disposing");}
}
5. 接口與抽象類的比較
特性 | 接口 | 抽象類 |
---|---|---|
實現 | 無 | 可以有 |
多繼承 | 支持 | 不支持 |
字段 | 不能有 | 可以有 |
構造函數 | 不能有 | 可以有 |
版本控制 | 添加成員會破壞實現 | 更靈活 |
訪問修飾符 | 默認public | 可控制 |
6. 接口的默認實現(C# 8.0+)
C# 8.0 引入了接口默認實現:
public interface ILogger
{void Log(string message);// 默認實現void LogError(string error){Log($"Error: {error}");}
}
7. 接口的實際應用示例
7.1 依賴注入
public interface IRepository
{void Save(Customer customer);Customer GetById(int id);
}public class SqlRepository : IRepository
{public void Save(Customer customer) { /* SQL實現 */ }public Customer GetById(int id) { /* SQL實現 */ }
}public class CustomerService
{private readonly IRepository _repository;public CustomerService(IRepository repository){_repository = repository;}public void AddCustomer(Customer customer){_repository.Save(customer);}
}
7.2 策略模式
public interface ISortStrategy
{void Sort(List<int> list);
}public class QuickSort : ISortStrategy
{public void Sort(List<int> list) { /* 快速排序實現 */ }
}public class BubbleSort : ISortStrategy
{public void Sort(List<int> list) { /* 冒泡排序實現 */ }
}public class Sorter
{private ISortStrategy _strategy;public Sorter(ISortStrategy strategy){_strategy = strategy;}public void Sort(List<int> list){_strategy.Sort(list);}
}
8. 接口的高級特性
8.1 接口繼承
接口可以繼承其他接口:
public interface IReadableRepository
{object GetById(int id);
}public interface IWritableRepository : IReadableRepository
{void Save(object entity);
}
8.2 泛型接口
public interface IRepository<T>
{void Add(T entity);T GetById(int id);IEnumerable<T> GetAll();
}
8.3 協變和逆變接口(C# 4.0+)
// 協變(out)
public interface IEnumerable<out T> { /*...*/ }// 逆變(in)
public interface IComparer<in T> { /*...*/ }
9. 接口的使用場景
- ?定義跨類別的行為?:如
IDisposable
- ?實現多繼承?:一個類可以實現多個接口
- ?依賴注入?:通過接口解耦依賴
- ?單元測試?:通過接口創建Mock對象
- ?插件架構?:定義擴展點
- ?策略模式?:定義算法族
10. 接口設計的最佳實踐
- ?單一職責?:每個接口應專注于一個特定功能
- ?命名規范?:以"I"開頭,如
IEnumerable
- ?避免過大接口?:防止實現類負擔過重
- ?優先組合而非繼承?:通過多個小接口組合功能
- ?考慮向后兼容?:添加新成員可能破壞現有實現
11. 總結
C# 中的接口是:
- 定義行為契約的強大工具
- 實現松耦合設計的關鍵
- 支持多繼承的機制
- 現代C#中功能不斷增強(默認實現等)
正確使用接口可以使代碼更加靈活、可測試和可維護,是面向對象設計和架構設計中的重要組成部分。