# 抽象类和接口的区别 概念: 抽象类和接口都可以用来做抽象,都能配合多态使用 但它们表达的语义不一样 简单理解: 抽象类更像“是什么” 接口更像“能做什么” 例如: 1. `Animal` 抽象类:表示狗、猫、鸟都是动物 2. `IFlyable` 接口:表示某个对象具备飞行能力 ---- # 先看抽象类 抽象类: ```csharp abstract class Animal { public string Name; public Animal(string name) { Name = name; } public void Eat() { Console.WriteLine(Name + "吃东西"); } public abstract void Speak(); } ``` 子类: ```csharp class Dog : Animal { public Dog(string name) : base(name) { } public override void Speak() { Console.WriteLine(Name + "汪汪"); } } ``` 抽象类适合: 1. 有明确父子关系 2. 要复用公共字段、构造函数、普通方法 3. 还要强制子类实现某些行为 一句话: 抽象类适合表达“这类东西的共同基础” ---- # 再看接口 接口: ```csharp interface IFlyable { void Fly(); } ``` 实现类: ```csharp class Bird : IFlyable { public void Fly() { Console.WriteLine("鸟飞"); } } class Plane : IFlyable { public void Fly() { Console.WriteLine("飞机飞"); } } ``` 接口适合: 1. 表达一种能力 2. 多个无关类型都能实现同一种行为 3. 一个类需要同时拥有多种能力 4. 调用方只关心能力,不关心具体身份 一句话: 接口适合表达“谁能做这件事” ---- # 核心区别 | 对比点 | 抽象类 | 接口 | |---|---|---| | 关键词 | `abstract class` | `interface` | | 主要表达 | 是什么 | 能做什么 | | 继承数量 | 一个类只能继承一个类 | 一个类可以实现多个接口 | | 成员实现 | 可以有普通实现,也可以有抽象成员 | 主要规定契约,要求实现类提供成员 | | 字段 | 可以有字段 | 通常不放实例字段 | | 构造函数 | 可以有构造函数 | 不能像类一样写实例构造函数 | | 适合场景 | 提取共同父类和公共代码 | 表达能力、规则、插件式扩展 | | 多态使用 | 可以用抽象类引用指向子类 | 可以用接口引用指向实现类 | ---- # 单继承和多实现 C# 中: 一个类只能继承一个父类 但可以实现多个接口 ```csharp abstract class Character { public string Name; } interface IMovable { void Move(); } interface IAttackable { void Attack(); } class Player : Character, IMovable, IAttackable { public void Move() { Console.WriteLine("移动"); } public void Attack() { Console.WriteLine("攻击"); } } ``` 理解: 1. `Player` 是一种 `Character` 2. `Player` 同时具备移动能力和攻击能力 3. 父类写一个,接口可以写多个 ---- # 什么时候用抽象类 适合用抽象类: ```csharp abstract class Enemy { public int Hp; public void TakeDamage(int damage) { Hp -= damage; } public abstract void Attack(); } ``` 因为: 1. 小怪、Boss、远程敌人都可以算敌人 2. 它们都有血量、受伤逻辑 3. 它们攻击方式不同 这种情况抽象类很合适: 有共同身份,也有公共代码 ---- # 什么时候用接口 适合用接口: ```csharp interface IDamageable { void TakeDamage(int damage); } ``` 实现者可能是: ```csharp class Player : IDamageable { public void TakeDamage(int damage) { } } class Enemy : IDamageable { public void TakeDamage(int damage) { } } class Box : IDamageable { public void TakeDamage(int damage) { } } ``` 玩家、敌人、箱子不是同一种父类关系,但它们都可以“受伤/受击”。 这种情况接口更合适: 没有共同身份,但有共同能力 ---- # 可以一起用 抽象类和接口不是二选一,经常会一起使用。 ```csharp abstract class Character { public string Name; public Character(string name) { Name = name; } public abstract void Update(); } interface IAttackable { void Attack(); } class Warrior : Character, IAttackable { public Warrior(string name) : base(name) { } public override void Update() { Console.WriteLine(Name + "更新状态"); } public void Attack() { Console.WriteLine(Name + "挥剑攻击"); } } ``` 理解: 1. `Warrior` 是一种 `Character` 2. `Warrior` 具备 `IAttackable` 能力 3. 抽象类负责共同身份和基础逻辑 4. 接口负责额外能力 ---- # 和多态的关系 抽象类多态: ```csharp Animal animal = new Dog(); animal.Speak(); ``` 接口多态: ```csharp IFlyable flyable = new Bird(); flyable.Fly(); ``` 它们都能做到: 用统一类型接收不同具体对象 运行时执行不同实现 区别在于: 1. 抽象类变量强调“它属于某个父类体系” 2. 接口变量强调“它拥有某个能力” ---- # 常见判断方法 问自己几个问题: 1. 这些类是不是同一种东西? - 是:优先考虑抽象类 - 不是:优先考虑接口 2. 是否需要复用字段、构造函数、普通方法? - 是:抽象类更合适 3. 一个类是否需要同时拥有多种能力? - 是:接口更合适 4. 调用方真正关心的是身份还是能力? - 关心身份:抽象类 - 关心能力:接口 ---- # 常见误区 误区1:接口就是更高级的抽象类 不是。 接口和抽象类不是上下级关系,而是用途不同 ---- 误区2:有公共方法就一定用抽象类 不一定。 如果这些类型没有真正的父子关系,硬抽象成父类可能违反[[里氏替换原则]] ---- 误区3:接口只能有方法 接口也可以有属性、索引器、事件等成员。 初学阶段先重点掌握方法和属性即可。 ---- # 注意 1. 抽象类和接口都不能直接创建对象 2. 抽象类用 `abstract class`,接口用 `interface` 3. 抽象类适合表达共同身份和公共代码 4. 接口适合表达能力和契约 5. 类只能继承一个父类,但可以实现多个接口 6. 抽象类和接口都可以配合多态 7. 设计时先看语义,不要只看语法 ---- # 一句话记忆 ==抽象类管“是谁的一种”,接口管“能做什么”。== 再压缩一点: ==同类用抽象类,能力用接口。== ---- # 面试/复习时怎么说 可以这样答: “抽象类和接口都能表达抽象,也都可以配合多态使用。 抽象类更强调父子关系和公共代码复用,一个类只能继承一个抽象类;接口更强调能力或契约,一个类可以实现多个接口。 如果多个类本质上是同一种东西,并且有公共字段、构造函数或普通方法,可以用抽象类;如果只是多个类型都有同一种能力,通常用接口更合适。” ---- 引用: 1. Microsoft Learn: [abstract (C# Reference)](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/abstract) 2. Microsoft Learn: [interface (C# Reference)](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/interface) 3. Microsoft Learn: [Interfaces](https://learn.microsoft.com/en-us/dotnet/csharp/fundamentals/types/interfaces) #抽象类 #接口 #核心