C# 面向对象核心:一文吃透多态(静态多态 + 动态多态完整讲解)
·
前言
封装、继承、多态是面向对象编程三大基石,前面我们学习了封装隐藏数据、继承复用代码,而多态是继承体系的最终落地,也是让代码具备高扩展性的关键特性。很多初学者分不清静态多态与动态多态,也不理解多态到底解决了什么开发痛点,今天结合通俗易懂的比喻 + 完整可运行案例,从零拆解多态全部知识点。
一、什么是多态
1. 通俗理解:同一个类型,不同行为
多态字面含义:多种形态。核心定义:同一个父类引用,指向不同子类实例,调用同名方法时执行各自子类独有的逻辑。
举个生活化例子:所有酒水都属于 “酒”(父类),剑南春、五粮液、酒鬼酒都是酒的子类。
plaintext
酒 a = 剑南春
酒 b = 五粮液
酒 c = 酒鬼酒
编译时只知道变量是 “酒”,只有运行时(喝下去)才能分辨具体是哪一款酒,每一种酒口感不同,对应代码里就是同名方法执行不同逻辑,这就是多态。
2. 专业定义
程序中父类引用变量指向的具体对象、方法调用逻辑,编译阶段无法确定,运行时才判定。无需修改原有业务代码,就能切换不同子类实现,一套引用适配多种实体,让程序拥有多种运行状态。
二、为什么要使用多态?从反面案例看懂痛点
我们用 QQ 宠物场景举例,直观感受没有多态时代码的缺陷。
1. 初始版本:无继承、无多态,代码极度冗余
分别创建猫、狗两个独立类,各自拥有Eat()进食方法;主人类需要单独写喂猫、喂狗两个方法。
public class Cat
{
public string Name { get; set; }
public int Health { get; set; }
public void Eat()
{
Health += 10;
Console.WriteLine("喵喵喵~鱼很好吃,健康值+10");
}
}
public class Dog
{
public string Name { get; set; }
public int Health { get; set; }
public void Eat()
{
Health += 15;
Console.WriteLine("汪汪汪~骨头不错哦,健康值+15");
}
}
// 主人类
public class Lady
{
public string Name { get; set; }
public Lady(string name) => Name = name;
// 单独喂猫
public void FeedCat(Cat cat) => cat.Eat();
// 单独喂狗
public void FeedDog(Dog dog) => dog.Eat();
}
调用测试:
static void Main(string[] args)
{
Lady lily = new Lady("lily");
Dog dog = new Dog() { Name = "大黄", Health = 60 };
Cat cat = new Cat() { Name = "蓝猫", Health = 50 };
lily.FeedDog(dog);
lily.FeedCat(cat);
}
代码存在两大致命问题
- 重复代码过多:猫、狗都有
Name、Health属性,重复定义; - 扩展性极差:后续新增鸟类、兔子宠物,必须修改
Lady主人类,新增FeedBird、FeedRabbit方法,违背开闭原则。
2. 第一次优化:抽取父类抽象类,复用重复代码
把宠物共有属性、抽象进食方法抽成父类Pet,猫狗继承并重写Eat():
public abstract class Pet
{
public string Name { get; set; }
public int Health { get; set; }
// 抽象进食方法,强制子类重写
public abstract void Eat();
}
public class Cat : Pet
{
public override void Eat()
{
Health += 10;
Console.WriteLine("喵喵喵~鱼很好吃,健康值+10");
}
}
public class Dog : Pet
{
public override void Eat()
{
Health += 15;
Console.WriteLine("汪汪汪~骨头不错哦,健康值+15");
}
}
此时解决了代码重复问题,但主人类FeedCat、FeedDog两个方法依然存在,新增宠物仍要修改主人类,扩展性问题没有根治。
3. 终极优化:引入多态,一套方法适配所有宠物
利用父类引用接收所有子类对象,主人只保留一个通用喂养方法:
public class Lady
{
public string Name { get; set; }
public Lady(string name) => Name = name;
// 父类Pet作为参数,兼容所有Pet子类
public void Feed(Pet pet)
{
pet.Eat();
}
}
测试调用:
static void Main(string[] args)
{
Lady lily = new Lady("lily");
Pet dog = new Dog() { Name = "大黄", Health = 60 };
Pet cat = new Cat() { Name = "蓝猫", Health = 50 };
// 同一个Feed方法,分别调用Dog、Cat的Eat实现
lily.Feed(dog);
lily.Feed(cat);
}
多态带来的核心优势
- 高扩展性:新增鸟类只需要新建
Bird : Pet并重写Eat(),主人类代码完全不用改动; - 代码精简:统一入口方法,消除大量重复业务函数;
- 解耦:上层主人类只依赖抽象父类,不依赖具体猫狗子类,降低代码耦合。
更多推荐



所有评论(0)