3.3 接口与抽象类
概述
接口(Interface)和抽象类(Abstract Class)是C#面向对象编程中实现多态和代码复用的核心机制。二者均用于定义行为规范,但在使用场景和特性上存在显著差异。
接口(Interface)
定义与特性
- 纯抽象契约:仅包含方法、属性、事件或索引器的声明,不包含实现。
- 多继承支持:一个类可实现多个接口。
- 隐式公开:所有成员默认
public,无需显式修饰。 - 版本兼容性:通过默认接口方法(C# 8.0+)可扩展接口而不破坏现有实现。
public interface ILogger
{
void Log(string message); // 方法声明
string LogLevel { get; set; } // 属性声明
}
使用场景
- 定义跨类层次的行为(如
IDisposable)。 - 需要多重继承时。
- 作为插件架构的基础(依赖注入)。
抽象类(Abstract Class)
定义与特性
- 部分实现:可包含抽象成员(
abstract修饰)和具体实现。 - 单继承限制:一个类只能继承一个抽象类。
- 构造器与字段:可定义构造函数和字段。
- 访问修饰符:支持
protected、internal等。
public abstract class Shape
{
public abstract double Area(); // 抽象方法
public void Print() => Console.WriteLine("Shape"); // 具体方法
}
使用场景
- 共享基类逻辑(如通用工具方法)。
- 需要控制子类初始化过程时(通过构造函数)。
- 定义模板方法模式。
对比与选择原则
| 特性 | 接口 | 抽象类 |
|---|---|---|
| 实现继承 | 多继承 | 单继承 |
| 成员实现 | 无(C# 8.0前) | 可部分实现 |
| 字段/构造函数 | 不支持 | 支持 |
| 版本兼容性 | 高(默认接口方法) | 低(修改可能破坏子类) |
选择建议:
- 优先使用接口实现松散耦合。
- 当需要共享代码或状态时使用抽象类。
高级主题
显式接口实现
解决多接口同名方法冲突:
interface I1 { void Method(); }
interface I2 { void Method(); }
class Demo : I1, I2
{
void I1.Method() => Console.WriteLine("I1");
void I2.Method() => Console.WriteLine("I2");
}
抽象类与接口的组合
常见模式:抽象类实现接口并提供基础实现:
public interface IRepository { void Save(); }
public abstract class RepositoryBase : IRepository
{
public virtual void Save() => Console.WriteLine("Base save");
}
常见问题
Q:何时选择抽象类而非接口?
A:当需要为派生类提供通用实现或强制特定初始化逻辑时。Q:接口可以包含字段吗?
A:不能(C# 10之前),但可通过自动属性模拟:int Value { get; set; }。Q:抽象类能否实现接口?
A:可以,且可选择实现部分或全部接口成员。
代码示例
// 接口定义
public interface IDrawable { void Draw(); }
// 抽象类实现接口
public abstract class Graphic : IDrawable
{
public abstract void Draw(); // 强制子类实现
protected void RenderBase() => Console.WriteLine("Rendering base");
}
// 具体类
public class Circle : Graphic
{
public override void Draw()
{
RenderBase();
Console.WriteLine("Drawing circle");
}
}
最佳实践:在设计大型系统时,遵循“接口隔离原则”(ISP),通过细粒度接口减少依赖关系。
