技术
抽象类和接口的设计原则
田敏
2024-11-181 分钟阅读CodingTipsC#
在 C# 中,抽象类和接口是面向对象编程中两种重要的设计工具,用于定义类型的规范。它们在用法和设计目的上有显著区别:
抽象类
特点
- 部分实现:抽象类可以包含已实现的方法(即非抽象方法)和未实现的方法(抽象方法)。
- 字段和属性:可以包含字段、属性和方法(静态或实例方法)。
- 构造函数:可以定义构造函数,用于初始化字段。
- 继承限制:一个类只能继承一个抽象类(单继承)。
- 访问修饰符:抽象类中的成员可以使用访问修饰符(如
public、protected、private等)。
使用场景
- 当需要共享代码的同时定义部分通用行为时。
- 当需要定义一组功能,同时为派生类提供一个基类实现。
- 当需要提供默认行为或**状态(字段)**支持时。
示例
abstract class Animal
{
public string Name { get; set; }
public void Eat() => Console.WriteLine($"{Name} is eating.");
public abstract void MakeSound(); // 抽象方法
}
class Dog : Animal
{
public override void MakeSound() => Console.WriteLine("Bark!");
}
接口
特点
- 全抽象:接口只包含方法签名、属性签名、事件等,不能包含实现(从 C# 8.0 起,接口支持默认实现)。
- 多继承支持:一个类可以实现多个接口。
- 没有状态:接口不能包含字段或构造函数。
- 只定义能力:接口定义的是类或结构必须具备的功能,而不关心如何实现。
使用场景
- 当需要描述一组能力,而这些能力可以在不相关的类中实现。
- 当需要支持多重继承时。
- 当需要定义一种标准行为,并让不同的类以不同方式实现。
示例
interface IFlyable
{
void Fly();
}
interface ISwimmable
{
void Swim();
}
class Duck : IFlyable, ISwimmable
{
public void Fly() => Console.WriteLine("Duck is flying.");
public void Swim() => Console.WriteLine("Duck is swimming.");
}
抽象类 vs 接口
| 特性 | 抽象类 | 接口 | | ------------ | ------------------------------ | ---------------------------- | | 实现方式 | 可以有部分实现 | 默认实现(C# 8.0+)或全抽象 | | 多继承 | 只支持单继承 | 支持多实现 | | 状态管理 | 可以包含字段、属性 | 无法包含字段,仅支持属性定义 | | 构造函数 | 可以定义构造函数 | 无构造函数 | | 使用场景 | 定义通用基类,提供部分默认行为 | 定义行为契约或能力扩展 |
什么时候用抽象类?
- 如果类之间存在明显的继承关系(
is-a关系),如Animal是Dog和Cat的基类。 - 如果需要提供通用的基础实现,并允许子类覆盖。
- 如果需要管理一些状态(字段)或提供构造函数初始化。
什么时候用接口?
- 如果类之间没有继承关系,但需要实现共同的行为(
can-do关系),如飞行能力 (IFlyable)。 - 如果需要支持多继承,让一个类实现多个行为。
- 如果需要确保所有实现类都有特定的方法,而不关心具体实现。
综合使用
有时会结合使用抽象类和接口,抽象类提供基础实现,接口定义额外的能力:
abstract class Animal
{
public string Name { get; set; }
public abstract void MakeSound();
}
interface IFlyable
{
void Fly();
}
class Bird : Animal, IFlyable
{
public override void MakeSound() => Console.WriteLine("Tweet!");
public void Fly() => Console.WriteLine($"{Name} is flying.");
}
版权协议:MIT返回列表