抽象方法
本课属于 Coddy Dart 学习旅程的“面向对象编程”单元。第 44 课,共 110 课。
抽象方法是在抽象类中声明且没有方法体的方法。它定义了方法签名,但将实现留给每个子类。任何继承抽象类的类都必须重写所有抽象方法,否则该类也会成为抽象类。
abstract class Animal {
// 抽象方法:没有方法体,必须由子类实现
String makeSound();
// 具体方法:有方法体,所有子类共用
void breathe() {
print('Breathing...');
}
}
class Dog extends Animal {
@override
String makeSound() {
return 'Woof!'; // 必须提供具体实现
}
}
class Cat extends Animal {
@override
String makeSound() {
return 'Meow!'; // 实现方式不同,方法签名相同
}
}如果子类忘记实现抽象方法,Dart 会给你一个编译错误。这正是抽象方法的意义所在:它们强制遵守契约。每个子类都一定有这个方法,因此你可以放心地在抽象类型的任何实例上调用它。
// 你可以把抽象类型用作变量的类型
Animal a = Dog();
print(a.makeSound()); // 汪!
Animal b = Cat();
print(b.makeSound()); // 喵!抽象类中的抽象方法与具体方法不同。具体方法有方法体,并会原样继承。抽象方法没有方法体,必须重写。
你可以在同一个抽象类中混合使用这两种方法,共享部分行为,同时强制子类为其他行为定义自己的方法。
| 特性 | 抽象方法 | 具体方法 |
|---|---|---|
| 是否有方法体 | 否 | 是 |
| 是否必须重写 | 是 | 否 |
| 用途 | 强制遵守约定 | 共享行为 |
| 适用位置 | 仅限抽象类 | 任何类 |
挑战
简单让我们来构建一个形状计算器,演示抽象方法的实际用法。你将定义一个包含抽象方法的抽象类,每种形状都必须以不同方式实现这些方法,然后通过一个通用接口使用这些形状。
你将把代码组织到 4 个文件中:
shape.dart:定义一个抽象类Shape,包含一个final字段color(String)和一个用于初始化它的构造函数。声明两个抽象方法:double area()和double perimeter()。再添加一个具体方法describe(),用于打印A [color] shape with area: [area] and perimeter: [perimeter]。由于area()和perimeter()是抽象方法,每个子类都会提供自己的计算方式,但describe()无需重写就能用于所有子类。circle.dart:创建一个继承Shape的Circle类。它包含一个final字段radius(double)。它的构造函数接收color和radius,并将color传递给super。实现area(),使其返回3.14 * radius * radius;实现perimeter(),使其返回2 * 3.14 * radius。rectangle.dart:创建一个继承Shape的Rectangle类。它包含final字段width和height(两者都是 double)。它的构造函数接收color、width和height,并将color传递给super。实现area(),使其返回width * height;实现perimeter(),使其返回2 * (width + height)。main.dart:导入所有文件。创建一个颜色为'red'、半径为5.0的Circle,再创建一个颜色为'blue'、宽度为4.0、高度为6.0的Rectangle。对每个形状调用describe()。然后创建一个包含这两个形状的List<Shape>,遍历这个列表,并为每个形状打印Area: [area]。
预期输出:
A red shape with area: 78.5 and perimeter: 31.400000000000002
A blue shape with area: 24.0 and perimeter: 20.0
Area: 78.5
Area: 24.0亲手试试
import 'shape.dart';
import 'circle.dart';
import 'rectangle.dart';
void main() {
// TODO: 创建一个颜色为 'red'、半径为 5.0 的 Circle
// TODO: 创建一个颜色为 'blue'、宽度为 4.0、高度为 6.0 的 Rectangle
// TODO: 对圆形调用 describe()
// TODO: 对矩形调用 describe()
// TODO: 创建一个包含这两个形状的 List<Shape>
// TODO: 遍历列表,为每个形状打印 "Area: [area]"
}
这节课包含一个小测验。开始学习即可作答,并记录你的进度。
面向对象编程中的所有课
自己练习: Dart 在线编译器