1. 引言
咱们试着从高处看看抽象:想象一个大办公室,不同员工做着不同的事。他们可能有个共同的职位——"员工",但每个人有自己的任务。可如果你是老板,只想让每个员工都能"完成工作",你根本不用关心他们怎么做:程序员写代码,会计打报表。这种“所有人都遵守的通用契约,细节交给专业的人”就是合理构建类层级的核心思想。
代码里长啥样?
一切都从基础的抽象类开始。它描述了所有子类必须会的最重要的东西。
public abstract class Employee
{
public string Name { get; }
public Employee(string name)
{
Name = name;
}
// 抽象方法——所有员工的契约
public abstract void DoWork();
}
接下来是派生类(子类)——程序员和会计:
public class Programmer : Employee
{
public Programmer(string name) : base(name) { }
public override void DoWork()
{
Console.WriteLine($"{Name} 写代码");
}
}
public class Accountant : Employee
{
public Accountant(string name) : base(name) { }
public override void DoWork()
{
Console.WriteLine($"{Name} 算钱");
}
}
注意啦:我们可以创建一个员工列表——不管是会计还是程序员,甚至你想加啥都行(抽象完全支持你这么干!)。
Employee[] office = new Employee[]
{
new Programmer("瓦夏"),
new Accountant("塔尼娅")
};
foreach (Employee emp in office)
{
emp.DoWork(); // 每个人做自己的事
}
瓦夏 写代码
塔尼娅 算钱
你看,现在多优雅、多通用,最重要的是可扩展。你想加个新类,比如Manager,原来的代码根本不用动!
2. 如何用抽象构建层级结构
几乎每本OOP教材都离不开动物的例子,咱们也来一波。
抽象类——“大Boss”
public abstract class Animal
{
public string Name { get; set; }
public Animal(string name)
{
Name = name;
}
// 所有动物都得会发出声音
public abstract void MakeSound();
// 但不是每个都能飞,所以:
public virtual void Fly()
{
Console.WriteLine("我不会飞。");
}
}
子类:必须会叫,也可以重写别的方法
public class Cat : Animal
{
public Cat(string name) : base(name) { }
public override void MakeSound()
{
Console.WriteLine($"{Name}: 喵!");
}
}
public class Dog : Animal
{
public Dog(string name) : base(name) { }
public override void MakeSound()
{
Console.WriteLine($"{Name}: 汪!");
}
}
public class Eagle : Animal
{
public Eagle(string name) : base(name) { }
public override void MakeSound()
{
Console.WriteLine($"{Name}: 啸叫!");
}
public override void Fly()
{
Console.WriteLine($"{Name} 在天上飞!");
}
}
来,组个动物园集合试试:
Animal[] zoo = new Animal[]
{
new Cat("巴尔西克"),
new Dog("沙里克"),
new Eagle("奥廖尔")
};
foreach (Animal animal in zoo)
{
animal.MakeSound();
animal.Fly();
}
巴尔西克: 喵!
我不会飞。
沙里克: 汪!
我不会飞。
奥廖尔: 啸叫!
奥廖尔 在天上飞!
你看,用啥子类都超简单:根本不用管集合里到底是啥对象。抽象负责“契约”,具体行为交给实现。
3. 多层抽象
抽象不只是基础类和直接子类的事。在复杂系统里,抽象经常分好几层,一个抽象类还能继承另一个。这就像千层蛋糕(或者像史莱克说的洋葱):每一层都藏掉不必要的细节,只留你关心的。
例子:交通工具的层级结构
. Vehicle (abstract)
/ | \
Car Airplane Boat
ElectricCar JetAirplane SailBoat
这里Vehicle定义了通用原则(比如Move()方法),但它不知道车和飞机怎么动,这得子类来定。更具体的类,比如ElectricCar或JetAirplane,还能加自己的细节,扩展功能。
层级结构的流程图:
. +------------------+
| Vehicle | <--- 抽象类
+------------------+
/ \
+-------+ +-------+
| Car | | Boat | <--- 中间抽象或具体类
+-------+ +-------+
代码:基础抽象类
public abstract class Vehicle
{
public string Model { get; }
public Vehicle(string model)
{
Model = model;
}
// 抽象方法
public abstract void Move();
}
中间抽象类
有时候中间层也得有自己的抽象!
public abstract class Car : Vehicle
{
public Car(string model) : base(model) { }
public override void Move()
{
Console.WriteLine($"{Model} 在路上跑。");
}
// 抽象方法——不是每辆车都用电:
public abstract void RefuelOrCharge();
}
具体实现
public class ElectricCar : Car
{
public ElectricCar(string model) : base(model) { }
public override void RefuelOrCharge()
{
Console.WriteLine($"{Model} 正在充电。");
}
}
public class GasolineCar : Car
{
public GasolineCar(string model) : base(model) { }
public override void RefuelOrCharge()
{
Console.WriteLine($"{Model} 加汽油。");
}
}
结果:多层抽象让你加新类和新功能都很轻松。
可视化:类层级结构示例
| 类 | 类型 | 抽象 | 父类 | 特殊行为 |
|---|---|---|---|---|
| Vehicle | 基础 | 是 | - | 抽象方法 Move() |
| Car | 中间 | 是 | Vehicle | 抽象 RefuelOrCharge() |
| ElectricCar | 最终 | 否 | Car | 实现 RefuelOrCharge() |
| GasolineCar | 最终 | 否 | Car | 实现 RefuelOrCharge() |
| Boat | 最终 | 否 | Vehicle | 实现 Move() |
4. 用抽象打造可扩展应用
实际好处:
- 代码灵活、可扩展:你可以加新类(比如新动物、新交通工具或新员工),不用改现有代码。你的循环/方法会自动支持新对象——只要它实现了抽象里定义的方法。
- 减少代码重复:通用属性和方法(比如名字、基础逻辑)只在抽象类里写一次,子类自动继承。
- 大型框架和系统常用:比如ASP.NET MVC有抽象的基础控制器(ControllerBase),WinForms有所有UI控件的抽象类Control。这样扩展框架时不会破坏已有部分。
哪里用得上?
- 各种大型系统:银行应用(员工、操作和交易)、游戏(游戏实体、角色)、商业应用(目录、商品、用户)、任何有层级和结构化数据的地方。
- 技术面试:会用抽象构建类、能讲清楚层级结构——面试常考。
- 程序架构:抽象让你在写逻辑前就能搭好“骨架”——方便团队开发、TDD(测试驱动开发)和后期维护。
5. 构建层级结构时的常见坑
错误1:忘了实现抽象方法。
如果你没实现基类的所有抽象成员,编译器绝对不让你创建子类实例。这是硬性规定——想变具体,必须全都实现。
错误2:想多继承抽象类。
C#不支持多继承,就算全是抽象类也不行。这是语言限制。如果你想“继承”多个来源的行为——用接口吧。接口就像抽象类,但更轻,没有实现。
错误3:没搞懂中间抽象类的意义。
这种类常用来归纳通用逻辑,防止创建“没定义全”的对象。比如Car可以是抽象的,这样没人能直接创建“车”,必须明确是汽油的、柴油的还是电的。
GO TO FULL VERSION