本章深入 Dart 的面向对象特性,涵盖类与对象、构造函数、私有成员、继承、抽象类、混入、枚举等核心概念。每个知识点配有完整代码示例和详细解析,帮助掌握 Dart 独特的 OOP 风格。
2.1 类与对象
知识点
- 类的定义 :使用
class关键字 - 成员变量:实例变量(可设置初始值)
- 成员方法:定义对象行为
- 对象创建 :
new关键字可选,通常省略 this关键字:指向当前实例,用于区分参数和成员变量
代码示例
dart
void main() {
// 创建对象
var person = Person('Alice', 25);
person.sayHello();
// 修改属性
person.age = 26;
person.sayHello();
}
class Person {
// 成员变量
String name;
int age;
// 构造函数
Person(this.name, this.age);
// 成员方法
void sayHello() {
print('Hello, I am $name, $age years old.');
}
}
解析
Person(this.name, this.age)是 Dart 的语法糖,自动将参数赋值给同名成员变量。- 实例变量默认是 public,没有
public/private关键字(使用_前缀实现私有)。 - Dart 中所有对象都继承自
Object类。
2.2 构造函数
知识点
- 默认构造函数:与类同名,无参数
- 命名构造函数 :
类名.名称(),用于多种构造方式 - 初始化列表:构造函数体执行前初始化成员变量
- 常量构造函数 :
const关键字,用于创建编译时常量对象 - 工厂构造函数 :
factory,用于控制实例的返回(如单例、缓存)
代码示例
dart
void main() {
// 普通构造
var p1 = Point(1, 2);
// 命名构造
var origin = Point.origin();
// 常量构造
const immutable = ImmutablePoint(3, 4);
// 工厂构造(单例)
var instance1 = Logger('main');
var instance2 = Logger('main');
print(identical(instance1, instance2)); // true(相同实例)
}
class Point {
double x, y;
// 普通构造函数 + 初始化列表
Point(this.x, this.y);
// 命名构造函数
Point.origin() : x = 0, y = 0;
// 重定向构造函数(调用另一个构造函数)
Point.fromJson(Map<String, double> json) : this(json['x']!, json['y']!);
}
class ImmutablePoint {
final double x, y;
// 常量构造函数(所有成员必须 final)
const ImmutablePoint(this.x, this.y);
}
class Logger {
final String name;
static final Map<String, Logger> _cache = {};
// 工厂构造函数:返回缓存实例
factory Logger(String name) {
return _cache.putIfAbsent(name, () => Logger._internal(name));
}
// 私有命名构造,供工厂使用
Logger._internal(this.name);
}
解析
- 初始化列表在构造函数体之前执行,适合初始化
final变量。 - 常量构造函数必须用
const调用,可放在常量上下文中,Flutter 中能提升性能。 - 工厂构造函数不创建新实例,可以返回已有对象或子类型。
2.3 私有成员
知识点
- 私有性 :使用
_前缀标识符为库私有 - 范围 :私有成员只能在当前
.dart文件内访问(库级别) - Getter / Setter:提供对私有字段的受控访问
代码示例
dart
void main() {
var bank = BankAccount('12345');
bank.deposit(100);
print(bank.balance); // 100
// bank._balance = 500; // 错误:私有成员不可访问
// bank._validate(); // 错误
}
class BankAccount {
String accountId;
double _balance; // 私有变量
BankAccount(this.accountId) : _balance = 0;
// Getter
double get balance => _balance;
// Setter(示例,通常不直接暴露 setter)
set balance(double value) {
if (value >= 0) _balance = value;
}
void deposit(double amount) {
if (amount > 0) {
_balance += amount;
_validate();
}
}
void _validate() { // 私有方法
if (_balance < 0) throw Exception('Negative balance');
}
}
解析
- Dart 没有
private关键字,以_开头即表示私有。 - 私有成员仍可通过反射访问,但不推荐。
- Getter 和 Setter 看起来像普通属性,但实际是方法调用。
2.4 Getter / Setter
知识点
- 计算属性 :通过
get关键字定义没有存储空间的值 - 自定义 Setter :通过
set关键字拦截赋值 - 使用方式 :像普通字段一样使用
.访问
代码示例
dart
void main() {
var rect = Rectangle(3, 4);
print(rect.area); // 12(计算属性)
rect.area = 20; // 调用 setter,修改宽高
print(rect.width); // 4.0
print(rect.height); // 5.0
}
class Rectangle {
double width, height;
Rectangle(this.width, this.height);
// Getter
double get area => width * height;
// Setter:设置面积时按比例调整宽高
set area(double value) {
var ratio = width / height;
width = (value * ratio).sqrt();
height = width / ratio;
}
}
解析
- Getter 没有参数,必须有返回值。
- Setter 只能有一个参数,没有返回值。
- 实际开发中常使用 Getter 暴露私有字段的只读版本。
2.5 继承
知识点
extends:单继承一个父类@override:标注重写父类方法(可选但推荐)super:调用父类的构造函数或方法- 方法重写:子类可以改变父类行为
代码示例
dart
void main() {
var dog = Dog('Buddy');
dog.speak(); // Buddy says Woof!
dog.eat(); // Buddy is eating.
var animal = Animal('Generic');
animal.speak(); // Generic makes sound.
}
class Animal {
String name;
Animal(this.name);
void speak() {
print('$name makes sound.');
}
void eat() {
print('$name is eating.');
}
}
class Dog extends Animal {
Dog(String name) : super(name);
@override
void speak() {
print('$name says Woof!');
}
// 可以选择不重写 eat,直接继承
}
解析
- 子类构造函数必须调用父类构造函数(默认调用无参构造,有参需手动
super(...))。 @override不是必需的,但有助于编译器检查和代码可读性。- Dart 不支持多继承(但可以通过混入实现类似效果)。
2.6 抽象类与接口
知识点
- 抽象类 :
abstract关键字,不能实例化,可包含抽象方法(无方法体) - 接口 :每个类都隐含是一个接口,使用
implements实现多个接口 - 区别 :
extends继承实现;implements只继承接口签名,必须重新实现所有方法
代码示例
dart
void main() {
// Animal a = Animal(); // 错误:抽象类不能实例化
Dog dog = Dog();
dog.speak();
dog.run();
// 使用接口实现
Robot robot = Robot();
robot.move();
}
abstract class Animal {
void speak(); // 抽象方法,无方法体
void breathe() {
print('Breathing');
}
}
class Dog implements Animal {
// 必须实现所有抽象方法
@override
void speak() => print('Woof!');
// 即使父类有实现,implements 后也要重新实现
@override
void breathe() => print('Dog breathing');
void run() => print('Running');
}
// 接口示例:定义一个移动接口
abstract class Movable {
void move();
}
class Robot implements Movable {
@override
void move() => print('Robot moving');
}
解析
- 抽象类可以包含具体方法,子类通过
extends继承。 - 一个类可以
implements多个接口,用逗号分隔。 - 推荐使用
abstract class定义纯接口,或使用mixin。
2.7 混入(Mixin)
知识点
mixin:定义可复用的代码片段,不含构造函数with:在类中使用混入,可组合多个on:限制混入只能用于特定类型的子类
代码示例
dart
void main() {
var bird = Bird();
bird.fly(); // Flying
bird.swim(); // Swimming
var fish = Fish();
fish.swim(); // Swimming
// fish.fly(); // 错误:Fish 没有 fly
}
// 定义混入
mixin Flyable {
void fly() => print('Flying');
}
mixin Swimmable {
void swim() => print('Swimming');
}
// 使用 with 组合混入
class Bird with Flyable, Swimmable {}
class Fish with Swimmable {}
// 限制混入作用域
mixin Walker on Animal {
void walk() => print('Walking');
}
class Animal {}
class Dog extends Animal with Walker {} // 合法,Walker 要求 on Animal
// class Table with Walker {} // 错误:Table 不是 Animal 的子类
解析
- 混入可以替代多重继承,解决代码复用问题。
- 如果一个混入使用了
on,则只能被on指定类型的子类使用。 - 混入不能有构造函数。
2.8 枚举
知识点
- 基本枚举 :
enum关键字,列出常量值 - 扩展枚举:Dart 2.17+ 支持字段、方法、构造函数
- 访问方式 :
EnumName.value,可获取index和name
代码示例
dart
void main() {
// 基本枚举
var color = Color.red;
print(color.index); // 0
print(color.name); // 'red'
switch (color) {
case Color.red:
print('红色');
break;
case Color.green:
print('绿色');
break;
case Color.blue:
print('蓝色');
break;
}
// 扩展枚举
print(Status.success.message);
print(Status.pending.displayName);
// 遍历枚举值
for (var status in Status.values) {
print(status);
}
}
// 基本枚举
enum Color { red, green, blue }
// 增强枚举(Dart 2.17+)
enum Status {
pending('等待中', 0),
success('成功', 1),
error('失败', -1);
final String displayName;
final int code;
const Status(this.displayName, this.code);
String get message => displayName;
}
解析
- 枚举可用于表示一组固定的常量。
- 增强枚举可以拥有实例变量、构造函数(必须是
const)和方法。 Enum.values可以获取所有枚举值的列表。
总结
第二章全面覆盖了 Dart 面向对象编程的核心概念,包括类、构造函数、私有成员、继承、抽象类/接口、混入以及枚举。这些知识是构建 Flutter 应用的基石,熟练掌握后可以编写出结构清晰、可复用的代码。下一章将进入 函数式编程与高阶特性。