继承基础
基本语法
class Animal {
String name;
Animal(this.name);
void makeSound() {
print('Some sound');
}
}
class Dog extends Animal {
Dog(String name) : super(name);
@override
void makeSound() {
print('Woof!');
}
}
构造函数继承
class Person {
String name;
int age;
Person(this.name, this.age);
// 命名构造函数
// 同样,非空字段走初始化列表,不能在构造体里赋值
Person.guest()
: name = 'Guest',
age = 18;
}
class Student extends Person {
String school;
// 调用父类构造函数
Student(String name, int age, this.school) : super(name, age);
// 调用父类命名构造函数
Student.guest(this.school) : super.guest();
}
抽象类
abstract class Shape {
// 抽象方法
double getArea();
double getPerimeter();
// 普通方法
void printInfo() {
print('Area: ${getArea()}');
print('Perimeter: ${getPerimeter()}');
}
}
class Rectangle extends Shape {
double width;
double height;
Rectangle(this.width, this.height);
@override
double getArea() => width * height;
@override
double getPerimeter() => 2 * (width + height);
}
接口实现
隐式接口
class Swimmer {
void swim() {
print('Swimming');
}
}
class Duck implements Swimmer {
@override
void swim() {
print('Duck swimming');
}
}
多接口实现
abstract class Flyer {
void fly();
}
abstract class Walker {
void walk();
}
class Bird implements Flyer, Walker {
@override
void fly() {
print('Flying');
}
@override
void walk() {
print('Walking');
}
}
多态
class Animal {
String name;
Animal(this.name);
void makeSound() {
print('Some sound');
}
}
class Cat extends Animal {
Cat(String name) : super(name);
@override
void makeSound() {
print('Meow!');
}
}
class Dog extends Animal {
Dog(String name) : super(name);
@override
void makeSound() {
print('Woof!');
}
}
void makeAnimalSound(Animal animal) {
animal.makeSound();
}
void main() {
Animal cat = Cat('Whiskers');
Animal dog = Dog('Rover');
makeAnimalSound(cat); // 输出: Meow!
makeAnimalSound(dog); // 输出: Woof!
}
完整示例
// 抽象类定义
abstract class Vehicle {
String brand;
String model;
Vehicle(this.brand, this.model);
void start();
void stop();
// 普通方法
void printInfo() {
print('$brand $model');
}
}
// 接口定义
abstract class Electric {
void charge();
}
abstract class Autonomous {
void selfDrive();
}
// 基础车辆类
class Car extends Vehicle {
int seats;
Car(String brand, String model, this.seats) : super(brand, model);
@override
void start() {
print('Car engine starting...');
}
@override
void stop() {
print('Car engine stopping...');
}
}
// 电动车类
class ElectricCar extends Car implements Electric {
int batteryCapacity;
ElectricCar(
String brand,
String model,
int seats,
this.batteryCapacity,
) : super(brand, model, seats);
@override
void charge() {
print('Charging electric car...');
}
@override
void start() {
print('Electric car starting silently...');
}
}
// 自动驾驶电动车
class AutonomousElectricCar extends ElectricCar implements Autonomous {
AutonomousElectricCar(
String brand,
String model,
int seats,
int batteryCapacity,
) : super(brand, model, seats, batteryCapacity);
@override
void selfDrive() {
print('Self-driving mode activated');
}
}
void main() {
// 创建不同类型的车辆
Car regularCar = Car('Toyota', 'Camry', 5);
ElectricCar tesla = ElectricCar('Tesla', 'Model 3', 5, 75);
AutonomousElectricCar waymo = AutonomousElectricCar('Waymo', 'One', 4, 100);
// 使用多态
List<Vehicle> vehicles = [regularCar, tesla, waymo];
for (var vehicle in vehicles) {
vehicle.printInfo();
vehicle.start();
vehicle.stop();
if (vehicle is Electric) {
(vehicle as Electric).charge();
}
if (vehicle is Autonomous) {
(vehicle as Autonomous).selfDrive();
}
print('---');
}
}
注意事项
- Dart 不支持多重继承
- 一个类可以实现多个接口
- 接口可以包含实现
- 注意方法重写的正确性
- 合理使用抽象类和接口
最佳实践
- 优先使用接口而不是继承
- 抽象类用于定义通用行为
- 合理使用多态
- 避免过深的继承层次
- 遵循里氏替换原则
实战观点:我的项目里几乎不用继承
说出来可能有点反直觉:我这几个 Flutter 项目(flutter_brightness、某物流冷链项目、ygking_json_to_dart_model)里,几乎看不到 extends。SerialService、JsonConverter、LuxData——全是独立的类,谁也不继承谁。
不是我不会用,而是被坑过之后的选择。继承的问题在于隐式耦合:子类自动获得父类的一切,包括你不想要的。Flutter 官方自己都在淡化继承——Widget 体系里,组合(child:/children:)才是主流,继承只用在极少数基础类上。
那什么时候用 implements(接口)?我的标准是:当你需要”多种实现可以互换”时。比如 flutter_brightness 里,如果以后要支持”除了串口,还能从网络读光照数据”,我会定义一个 abstract class LightSensorReader,然后 SerialLightSensorReader implements LightSensorReader、NetworkLightSensorReader implements LightSensorReader。接口的价值在”第二个实现”出现时才兑现——只有一个实现时,写接口就是过度设计。
Dart 里还有个细节:所有的类都隐式定义了接口(class A 可以直接被 implements,不需要 abstract)。这个设计让”先写实现、后抽接口”很顺滑——SerialService 现在是具体类,哪天需要多实现,直接 implements SerialService 就行,不用改原代码。
参考:Dart 官方文档(dart.dev)“Classes” 章节
总结
Dart 里 extends 是”是一种”,implements 是”能干什么”——大部分时候后者更够用。继承层级超过两层就该停下来想想是不是该用组合;接口等到第二个实现冒头再抽,提前写只是自我感动。
