1. Dart中的类基础概念
在Dart语言中,类(class)是面向对象编程的核心构建块。与Java、C#等语言类似,Dart的类提供了封装数据和行为的能力,但又有其独特的语法特性。
Dart的类定义使用class关键字,后跟类名。类名通常采用大驼峰命名法(PascalCase)。一个最简单的类定义如下:
dart复制class Person {
// 类成员将在这里定义
}
与Python不同,Dart是静态类型语言,因此类成员需要显式声明类型。与TypeScript相似,Dart也支持类型推断,但显式声明类型能让代码更清晰。
注意:Dart 2.12版本引入了空安全特性,这意味着默认情况下所有类型都是非空的。如果需要允许null值,需要在类型后添加问号(如
String?)。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 类的成员变量与方法
2.1 实例变量
实例变量(也称为字段或属性)是每个类实例特有的数据。在Dart中,实例变量可以声明为公开的或私有的:
dart复制class Person {
String name; // 公开实例变量
int _age; // 私有实例变量(以下划线开头)
String? nickname; // 可空的字符串变量
}
与Java不同,Dart没有public、private等访问修饰符。默认情况下,以下划线(_)开头的成员是库私有的,只能在当前库中访问。
2.2 构造函数
Dart提供了几种构造函数定义方式:
- 默认构造函数:
dart复制class Person {
String name;
int age;
Person(this.name, this.age); // 简洁的构造函数语法
}
- 命名构造函数:
dart复制Person.fromJson(Map<String, dynamic> json) {
name = json['name'];
age = json['age'];
}
- 初始化列表:
dart复制Person(String name, int age)
: name = name.toUpperCase(),
age = age {
print('Person created: $name, $age');
}
与C++的构造函数初始化列表类似,Dart的初始化列表在构造函数体执行前运行。
2.3 方法
类方法定义与函数类似,但位于类内部:
dart复制class Person {
void introduce() {
print('Hello, I am $name');
}
// Getter方法
String get fullName => '$name Smith';
// Setter方法
set age(int value) {
if (value > 0) {
_age = value;
}
}
}
Dart支持特殊的getter和setter方法,它们看起来像属性但实际上是方法调用。
3. 类的继承与多态
3.1 继承
Dart使用extends关键字实现继承:
dart复制class Employee extends Person {
String department;
Employee(String name, int age, this.department) : super(name, age);
}
与Kotlin的open class不同,Dart中所有类默认都是可继承的,除非标记为final。
3.2 方法重写
使用@override注解明确表示方法重写:
dart复制class Employee extends Person {
@override
void introduce() {
print('I work in $department department');
super.introduce(); // 调用父类方法
}
}
3.3 抽象类与接口
Dart的抽象类使用abstract关键字:
dart复制abstract class Animal {
void makeSound(); // 抽象方法
}
class Dog implements Animal {
@override
void makeSound() {
print('Woof!');
}
}
与Java不同,Dart没有专门的interface关键字。任何类都可以作为接口使用,使用implements关键字实现。
4. 高级类特性
4.1 工厂构造函数
工厂构造函数允许返回缓存实例或子类实例:
dart复制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);
}
这种模式在需要控制实例创建时非常有用,类似于设计模式中的单例模式。
4.2 Mixins
Dart通过mixin提供多重继承的替代方案:
dart复制mixin Musical {
void playMusic() {
print('Playing music');
}
}
class Performer with Musical {
// 现在Performer类有playMusic方法
}
Mixins与Kotlin的接口默认方法类似,但更灵活。它们可以包含具体实现而不仅仅是抽象定义。
4.3 扩展方法
Dart 2.7引入了扩展方法:
dart复制extension NumberParsing on String {
int parseInt() {
return int.parse(this);
}
}
void main() {
print('42'.parseInt()); // 输出: 42
}
这类似于C#的扩展方法,允许为现有类添加新功能而不修改原始类。
5. 类与空安全
Dart的空安全特性对类设计有重要影响:
dart复制class Person {
late String name; // 延迟初始化,保证在使用前被赋值
int? age; // 可空的年龄
Person(this.name);
void celebrateBirthday() {
age = (age ?? 0) + 1; // 如果age为null,使用0作为默认值
}
}
late关键字表示变量将在使用前被初始化,而?表示变量可以为null。这种设计有助于消除空指针异常。
6. 类与JSON序列化
在实际应用中,类经常需要与JSON相互转换:
dart复制import 'dart:convert';
class User {
final String name;
final String email;
User(this.name, this.email);
// 将User实例转换为Map
Map<String, dynamic> toJson() => {
'name': name,
'email': email,
};
// 从Map创建User实例
factory User.fromJson(Map<String, dynamic> json) {
return User(
json['name'] as String,
json['email'] as String,
);
}
}
void main() {
// 序列化
final user = User('Alice', 'alice@example.com');
final json = jsonEncode(user.toJson());
print(json);
// 反序列化
final decodedUser = User.fromJson(jsonDecode(json));
print(decodedUser.email);
}
对于复杂项目,可以考虑使用json_serializable等代码生成工具来自动生成序列化代码。
7. 类的设计模式实践
7.1 单例模式
dart复制class Database {
static final Database _instance = Database._internal();
factory Database() {
return _instance;
}
Database._internal(); // 私有构造函数
}
7.2 建造者模式
dart复制class Pizza {
final Size size;
final List<String> toppings;
Pizza._(this.size, this.toppings);
factory Pizza.builder(PizzaBuilder builder) {
return Pizza._(builder.size, builder.toppings);
}
}
class PizzaBuilder {
Size size = Size.medium;
final List<String> toppings = [];
PizzaBuilder addTopping(String topping) {
toppings.add(topping);
return this;
}
Pizza build() {
return Pizza.builder(this);
}
}
7.3 观察者模式
dart复制abstract class Subject {
final List<Observer> _observers = [];
void attach(Observer observer) {
_observers.add(observer);
}
void notify() {
for (final observer in _observers) {
observer.update();
}
}
}
abstract class Observer {
void update();
}
8. 类的最佳实践与常见问题
8.1 最佳实践
- 保持类单一职责:每个类应该只有一个改变的理由
- 优先使用组合而非继承:除非有明显的"is-a"关系
- 使用final修饰不可变字段:提高线程安全性和可预测性
- 合理使用私有成员:封装内部实现细节
- 为公共API添加文档注释:使用
///文档注释
8.2 常见问题
- 忘记调用super:在重写方法时,特别是
initState()等生命周期方法 - 不必要地使用late:只有在确实需要延迟初始化时才使用
- 过度使用静态成员:可能导致测试困难和紧耦合
- 忽略空安全:可能导致运行时异常
- 深层继承层次:使代码难以理解和维护
我在实际项目中发现,合理使用mixin和扩展方法可以显著减少重复代码,但过度使用会导致代码结构混乱。一个好的经验法则是:当某个功能被三个以上类共享时,考虑提取为mixin或扩展方法。
