Dart 中的抽象类
最后修改于 2025 年 5 月 25 日
本教程探讨 Dart 中的抽象类,这是创建类层次结构和定义接口的关键功能。抽象类能够实现多态和代码重用,同时强制执行实现契约。
抽象类概述
Dart 中的抽象类是无法直接实例化的不完整蓝图。它们定义了一个具体子类必须实现的契约。抽象类可以包含已实现的方法和抽象方法的声明。
与普通类不同,抽象类可以包含未实现的方法(抽象方法)。任何具体的(非抽象)子类都必须实现这些方法。抽象类使用 abstract 修饰符声明。
| 功能 | 抽象类 | 普通类 |
|---|---|---|
| 实例化 | 不能实例化 | 可以实例化 |
| 方法 | 可以包含抽象方法 | 所有方法都已实现 |
| 目的 | 定义接口/行为 | 完整实现 |
| 继承 | 必须继承 | 可直接使用 |
当您想在多个相关类之间共享代码,同时强制执行某些方法的实现时,抽象类特别有用。它们介于接口(纯契约)和具体类(完整实现)之间。
基本抽象类
本示例演示了一个具有具体方法和抽象方法的简单抽象类。我们将创建一个抽象的 Shape 类,它为所有形状定义了通用行为。
abstract class Shape {
// Abstract method (no implementation)
double area();
// Concrete method
void describe() {
print('This shape has an area of ${area()}');
}
}
class Circle extends Shape {
final double radius;
Circle(this.radius);
@override
double area() => 3.14159 * radius * radius;
}
class Square extends Shape {
final double side;
Square(this.side);
@override
double area() => side * side;
}
void main() {
// var shape = Shape(); // Error: Can't instantiate abstract class
var circle = Circle(5.0);
var square = Square(4.0);
circle.describe();
square.describe();
}
Shape 抽象类声明了一个抽象的 area 方法,子类必须实现该方法。它还提供了一个具体的 describe 方法,该方法使用抽象方法。这说明了抽象类如何混合已实现和未实现的功能。
Circle 和 Square 类继承自 Shape,并提供了它们对 area 的特定实现。该示例表明我们不能直接实例化 Shape - 我们必须创建具体子类的实例。
$ dart run basic_abstract.dart This shape has an area of 78.53975 This shape has an area of 16.0
抽象类作为接口
Dart 没有单独的接口关键字 - 抽象类通常用作接口。本示例展示了如何使用抽象类来定义多个类可以不同地实现的契约。
abstract class PaymentProcessor {
void processPayment(double amount);
void refundPayment(double amount);
}
class CreditCardProcessor implements PaymentProcessor {
@override
void processPayment(double amount) {
print('Processing credit card payment: \$$amount');
}
@override
void refundPayment(double amount) {
print('Refunding credit card payment: \$$amount');
}
}
class PayPalProcessor implements PaymentProcessor {
@override
void processPayment(double amount) {
print('Processing PayPal payment: \$$amount');
}
@override
void refundPayment(double amount) {
print('Refunding PayPal payment: \$$amount');
}
}
void processOrder(PaymentProcessor processor, double amount) {
processor.processPayment(amount);
}
void main() {
var creditCard = CreditCardProcessor();
var paypal = PayPalProcessor();
processOrder(creditCard, 100.0);
processOrder(paypal, 50.0);
}
PaymentProcessor 抽象类定义了一个支付处理器必须实现的接口。与使用 extends 不同,使用 implements 要求子类提供所有方法的实现,包括抽象类的具体方法。
该示例演示了多态性 - processOrder 函数接受任何 PaymentProcessor 实现。这种模式对于创建可插入式架构非常有用,因为实现可以轻松替换。
$ dart run interface_abstract.dart Processing credit card payment: $100.0 Processing PayPal payment: $50.0
带属性的抽象类
抽象类可以定义子类必须实现的抽象属性。本示例显示了一个同时具有抽象属性和具体属性的抽象类。
abstract class Vehicle {
// Abstract property
String get name;
// Concrete property
int wheels = 4;
// Abstract method
void move();
// Concrete method using abstract members
void describe() {
print('$name with $wheels wheels is moving');
move();
}
}
class Car extends Vehicle {
@override
final String name;
Car(this.name);
@override
void move() {
print('Vroom vroom!');
}
}
class Bicycle extends Vehicle {
@override
final String name = 'Bicycle';
@override
int wheels = 2;
@override
void move() {
print('Pedaling...');
}
}
void main() {
var car = Car('Tesla');
var bike = Bicycle();
car.describe();
bike.describe();
}
Vehicle 抽象类声明了一个抽象的 name 属性和 move 方法,同时提供了默认的 wheels 值和具体的 describe 方法。Car 和 Bicycle 类以不同的方式实现这些。
这演示了抽象类如何定义接口的必需和可选方面。wheels 属性展示了具体子类如何覆盖抽象类的默认值。
$ dart run properties_abstract.dart Tesla with 4 wheels is moving Vroom vroom! Bicycle with 2 wheels is moving Pedaling...
带 Mixin 的多重继承
Dart 的 Mixin 可以与抽象类一起使用,以实现类似多重继承的行为。本示例将抽象类与 mixin 结合起来,以创建灵活的类层次结构。
abstract class Animal {
String get name;
void makeSound();
}
mixin Walker {
void walk() {
print('Walking...');
}
}
mixin Swimmer {
void swim() {
print('Swimming...');
}
}
class Dog extends Animal with Walker {
@override
final String name;
Dog(this.name);
@override
void makeSound() => print('Woof!');
}
class Duck extends Animal with Walker, Swimmer {
@override
final String name;
Duck(this.name);
@override
void makeSound() => print('Quack!');
}
void main() {
var dog = Dog('Buddy');
var duck = Duck('Donald');
dog.makeSound();
dog.walk();
duck.makeSound();
duck.walk();
duck.swim();
// Can't instantiate abstract class
// var animal = Animal();
}
Animal 抽象类定义了核心的动物行为,而 Walker 和 Swimmer mixin 则添加了特定的功能。Dog 和 Duck 类以不同的方式组合了这些功能。
这种模式允许灵活的代码重用,同时保持清晰的类层次结构。抽象类确保满足某些契约,而 mixin 提供模块化行为,可以根据需要混合使用。
$ dart run mixin_abstract.dart Woof! Walking... Quack! Walking... Swimming...
抽象类中的工厂构造函数
抽象类可以具有返回具体子类实例的工厂构造函数。这对于创建对象而不暴露具体实现很有用。
abstract class Logger {
void log(String message);
factory Logger(String type) {
switch (type.toLowerCase()) {
case 'console':
return ConsoleLogger();
case 'file':
return FileLogger();
default:
throw ArgumentError('Unknown logger type: $type');
}
}
}
class ConsoleLogger implements Logger {
@override
void log(String message) {
print('CONSOLE: $message');
}
}
class FileLogger implements Logger {
@override
void log(String message) {
print('FILE: $message (written to log file)');
}
}
void main() {
var consoleLogger = Logger('console');
var fileLogger = Logger('file');
consoleLogger.log('This is a console message');
fileLogger.log('This should go to a file');
try {
var unknownLogger = Logger('database');
} catch (e) {
print('Error: $e');
}
}
Logger 抽象类定义了一个工厂构造函数,该构造函数根据输入参数返回不同的日志记录器实现。这会将具体类隐藏起来,使消费者只能与抽象接口进行交互。
这种模式对于创建在运行时需要确定确切实现的对象的很有用。它提供了一种封装对象创建逻辑的干净方法,同时为客户端维护简单的接口。
$ dart run factory_abstract.dart CONSOLE: This is a console message FILE: This should go to a file (written to log file) Error: ArgumentError: Unknown logger type: database
来源
Dart 抽象类
Dart Mixins
Dart 工厂构造函数
抽象类是 Dart 中创建灵活、可维护类层次结构的强大工具。它们能够实现多态、代码重用和清晰的接口定义。通过将抽象类与 mixin 和工厂构造函数结合使用,您可以构建复杂而简洁的面向对象设计。
作者
列出 所有 Dart 教程。