好处:
Flutter 和 Dart 提供了许多强大的内置特性,可以是我们的代码可读性提高,使代码变得:
✅ 更短 (更少的样板代码)
✅ 更易维护 (逻辑集中,意图明确)
✅ 更易理解 (队友接手不再骂娘)
✅ 更少重复 (DRY 原则的践行)
✅ 更现代(符合 Flutter 社区的最佳实践)
1. Extensions:告别 Utils 地狱
在认识 Extension 之前,我的项目里充斥着 StringUtils、DateUtils 这类静态工具类。
旧世界:
class StringUtils {
static bool isValidEmail(String value) {
return value.contains('@');
}
}
// 使用
StringUtils.isValidEmail(email);
新世界:
extension EmailValidator on String {
bool get isValidEmail => contains('@');
}
// 使用
email.isValidEmail;
重构收益:
-
语义归属:功能不再流浪在全局工具类中,而是归属于它操作的数据类型。
-
链式调用 :
user.email.isValidEmail比 StringUtils.isValidEmail(user.email)更符合直觉。 -
减少噪音 :不再需要导入一堆
*_utils.dart文件。
我现在用它做 :
字符串格式化、日期处理、表单校验、Context 快捷访问(如 context.theme)、主题获取。
2. Const Constructors:免费的性能午餐
我曾长期忽视 const,因为不加它,一切似乎也运行良好。
旧世界:
Text('Hello'); // 每次重建
新世界:
const Text('Hello'); // 缓存复用
重构收益:
-
性能红利:当 Widget 永不改变时,Flutter 可以复用它,而非反复重建。单个收益微小,但在复杂页面上累积效应惊人。
-
IDE 助攻 :现代 IDE 会高亮提示可加
const的地方,这成为了一种代码质量的即时反馈。 -
意图明确 :
const向阅读者宣告:"此部件是不可变的",增强了代码的可预测性。
原则 :能加 const 的地方,一定要加。
3. Mixins:优雅的复用,而非继承的枷锁
最初我以为 Mixin 是框架开发者才用的高级特性。
事实证明,它是解决代码复用的利器。
旧世界:
class HomeController {
void fetchData() {
debugPrint('Fetching data...'); // 到处复制粘贴的日志逻辑
}
}
新世界:
mixin LoggerMixin {
void log(String message) {
debugPrint(message);
}
}
class HomeController with LoggerMixin {
void fetchData() {
log('Fetching data...'); // 直接复用
}
}
重构收益:
-
组合优于继承:无需为了复用一段逻辑而强行继承。
-
关注点分离:将日志、埋点、校验等横切关注点(Cross-cutting Concerns)抽离到 Mixin 中。
-
减少样板:避免在多个类中重复编写相同的辅助方法。
适用场景:日志、埋点、表单校验、生命周期辅助、通用业务逻辑。
4. Records:轻量级数据的终点
Records 刚出来时,我觉得"不就是个元组吗",然后无视了它。
结果我还在为了返回两个值而创建大量的 UserInfo、Result 类。
旧世界:
class UserInfo {
final String name;
final int age;
UserInfo(this.name, this.age);
}
UserInfo getUser() => UserInfo('Ravi', 25);
新世界:
(String, int) getUser() => ('Ravi', 25);
// 使用
final (name, age) = getUser();
重构收益:
-
消灭样板类:对于临时、轻量的数据结构,无需创建完整的 Model 类。
-
解构赋值 :
final (name, age)的语法极其优雅,一眼便知数据流向。 -
模式匹配好搭档:Records 与 Pattern Matching 结合,威力无穷。
原则 :仅在数据需要序列化、持久化或复杂逻辑时才创建 Class;否则,用 Record。
5. Pattern Matching:消灭 if-else 的终极武器
第一次看到 Pattern Matching,我觉得它晦涩难懂,于是敬而远之。
后来才发现,它是消灭大量重复条件逻辑的终极武器。
旧世界:
Widget buildWidget(String status) {
if (status == 'loading') return LoadingWidget();
if (status == 'success') return SuccessWidget();
if (status == 'error') return ErrorWidget();
return SizedBox();
}
新世界:
Widget buildWidget(String status) => switch (status) {
'loading' => LoadingWidget(),
'success' => SuccessWidget(),
'error' => ErrorWidget(),
_ => SizedBox(),
};
重构收益:
-
穷尽性检查(Exhaustiveness):编译器会告诉你是否漏掉了某个状态,将运行时错误消灭在编译期。
-
声明式 UI:代码描述的是"是什么",而非"怎么做",可读性大幅提升。
-
状态机友好:在 BLoC、Riverpod、Clean Architecture 中处理状态流转时,它是绝佳的伴侣。
6. Collection If & For:UI 逻辑的净化
我曾花了数月时间编写不必要的 List 操作代码。
旧世界:
final widgets = <Widget>[];
if (isAdmin) {
widgets.add(const AdminBanner());
}
for (final user in users) {
widgets.add(UserTile(user));
}
新世界:
final widgets = [
if (isAdmin) const AdminBanner(),
for (final user in users) UserTile(user),
];
重构收益:
-
UI 即代码:UI 结构与代码逻辑高度一致,一眼看清渲染结果。
-
减少中间态 :不再需要创建临时 List 并进行
add操作。 -
可读性暴增:虽然改动微小,但对 UI 代码的清晰度提升巨大。
7. Cascade Operator (..):链式初始化的美学
另一个因"看着奇怪"而被我回避的特性。
旧世界:
final controller = TextEditingController();
controller.text = 'Hello';
controller.selection = TextSelection.collapsed(offset: controller.text.length);
新世界:
final controller = TextEditingController()
..text = 'Hello'
..selection = TextSelection.collapsed(offset: 5);
重构收益:
-
减少重复 :不再重复书写
controller.。 -
初始化流畅:对象的构建与配置一气呵成,符合流式编程的美学。
-
意图清晰:一眼看出这是对同一个对象的连续操作。