痛点场景:复杂的对话框配置
假设你需要创建一个多功能对话框:
CustomDialog(
title: '警告',
content: '确定要删除吗?',
titleStyle: TextStyle(fontSize: 20, color: Colors.red),
contentStyle: TextStyle(fontSize: 16),
backgroundColor: Colors.grey[200],
barrierDismissible: false,
positiveButton: DialogButton(
text: '确认',
color: Colors.red,
onPressed: () => print('Confirmed'),
),
negativeButton: DialogButton(
text: '取消',
color: Colors.grey,
onPressed: () => print('Cancelled'),
),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10),
),
// 还有10个参数...
)
问题爆发点:
- 🚨 构造函数参数爆炸(难以维护和使用)
- 💥 必须记住参数顺序
- 🔥 可选参数处理困难(需要传入大量null)
- 🌋 相似组件创建需要重复代码
建造者模式解决方案
核心思想: 将复杂对象的构建与其表示分离,使同样的构建过程可以创建不同的表示。
四个关键角色:
- 产品(Product): 最终要构建的复杂对象(如对话框)
- 抽象建造者(Builder): 定义构建步骤的接口
- 具体建造者(ConcreteBuilder): 实现构建步骤
- 指挥者(Director): 控制构建过程(Flutter中常可省略)
Flutter对话框建造者实现
1. 定义产品类
class DialogConfig {
String? title;
String? content;
TextStyle? titleStyle;
TextStyle? contentStyle;
Color? backgroundColor;
bool barrierDismissible = true;
DialogButton? positiveButton;
DialogButton? negativeButton;
ShapeBorder? shape;
// 其他配置项...
}
class DialogButton {
final String text;
final Color color;
final VoidCallback onPressed;
DialogButton({
required this.text,
required this.color,
required this.onPressed,
});
}
2. 创建建造者类
class DialogBuilder {
final DialogConfig _config = DialogConfig();
// 设置标题
DialogBuilder title(String title, {TextStyle? style}) {
_config.title = title;
_config.titleStyle = style;
return this;
}
// 设置内容
DialogBuilder content(String content, {TextStyle? style}) {
_config.content = content;
_config.contentStyle = style;
return this;
}
// 设置背景
DialogBuilder backgroundColor(Color color) {
_config.backgroundColor = color;
return this;
}
// 添加确认按钮
DialogBuilder withPositiveButton(String text, {
required VoidCallback onPressed,
Color color = Colors.blue,
}) {
_config.positiveButton = DialogButton(
text: text,
color: color,
onPressed: onPressed,
);
return this;
}
// 构建最终产品
Widget build() {
return AlertDialog(
title: _config.title != null
? Text(_config.title!, style: _config.titleStyle)
: null,
content: _config.content != null
? Text(_config.content!, style: _config.contentStyle)
: null,
backgroundColor: _config.backgroundColor,
actions: [
if (_config.negativeButton != null)
TextButton(
style: TextButton.styleFrom(
foregroundColor: _config.negativeButton!.color,
),
onPressed: _config.negativeButton!.onPressed,
child: Text(_config.negativeButton!.text),
),
if (_config.positiveButton != null)
TextButton(
style: TextButton.styleFrom(
foregroundColor: _config.positiveButton!.color,
),
onPressed: _config.positiveButton!.onPressed,
child: Text(_config.positiveButton!.text),
),
],
shape: _config.shape,
);
}
}
3. 在Flutter中使用
// 基础用法
showDialog(
context: context,
builder: (_) => DialogBuilder()
.title('警告', style: TextStyle(color: Colors.red))
.content('确定要删除这个文件吗?')
.withPositiveButton('删除', onPressed: () => Navigator.pop(context))
.build()
);
// 复杂用法
final deleteDialog = DialogBuilder()
.title('永久删除', style: TextStyle(fontWeight: FontWeight.bold))
.content('此操作将永久删除数据,不可恢复!')
.backgroundColor(Colors.grey[100]!)
.withPositiveButton('确认删除',
onPressed: () => _deleteItem(),
color: Colors.red,
)
.withNegativeButton('取消')
.build();
showDialog(context: context, builder: (_) => deleteDialog);
Flutter框架中的建造者模式
实际上,Flutter自身大量使用了建造者模式的变体:
1. TextStyle
的copyWith方法
TextStyle style = TextStyle(
fontSize: 16,
color: Colors.black,
).copyWith(
fontWeight: FontWeight.bold,
decoration: TextDecoration.underline,
);
2. ThemeData
的构造方式
final theme = ThemeData.light().copyWith(
primaryColor: Colors.blue,
buttonTheme: ButtonThemeData(
buttonColor: Colors.blue[700],
),
);
3. BoxDecoration
的链式配置
BoxDecoration(
color: Colors.blue,
borderRadius: BorderRadius.circular(10),
boxShadow: [
BoxShadow(color: Colors.black12, blurRadius: 6),
],
)
高级应用:响应式布局建造者
创建一个能自动适应不同屏幕尺寸的布局建造者:
class ResponsiveBuilder {
final List<Widget> _children = [];
double _spacing = 16.0;
Axis _direction = Axis.vertical;
int _crossAxisCount = 2;
ResponsiveBuilder addChild(Widget child) {
_children.add(child);
return this;
}
ResponsiveBuilder spacing(double value) {
_spacing = value;
return this;
}
ResponsiveBuilder horizontal() {
_direction = Axis.horizontal;
return this;
}
ResponsiveBuilder columns(int count) {
_crossAxisCount = count;
return this;
}
Widget build() {
return LayoutBuilder(
builder: (context, constraints) {
if (constraints.maxWidth > 600) {
return GridView.count(
crossAxisCount: _crossAxisCount,
childAspectRatio: 1.0,
mainAxisSpacing: _spacing,
crossAxisSpacing: _spacing,
children: _children,
);
} else {
return ListView.separated(
scrollDirection: _direction,
itemCount: _children.length,
separatorBuilder: (_, __) => SizedBox(
width: _direction == Axis.horizontal ? _spacing : 0,
height: _direction == Axis.vertical ? _spacing : 0,
),
itemBuilder: (context, index) => _children[index],
);
}
},
);
}
}
// 使用示例
ResponsiveBuilder()
.addChild(ProductCard(product1))
.addChild(ProductCard(product2))
.spacing(20)
.columns(3)
.build()
建造者模式最佳实践
何时使用建造者模式:
- 对象需要多个步骤或复杂配置才能创建
- 构造函数参数超过4个
- 需要创建不可变对象但又要灵活配置
- 相同构建过程需要创建不同表示
Flutter特化技巧:
// 使用可选命名参数简化初始创建 DialogBuilder({String? title, String? content}) { if (title != null) _config.title = title; if (content != null) _config.content = content; } // 添加预置配置 DialogBuilder.error() { return DialogBuilder() .titleColor(Colors.red) .backgroundColor(Colors.red[50]!); } // 支持运算符重载 DialogBuilder operator <<(Widget child) { addChild(child); return this; }
性能优化:
// 使用memoization缓存常用配置 class DialogBuilder { static final Map<String, DialogConfig> _presets = {}; static DialogBuilder preset(String name) { if (!_presets.containsKey(name)) { _presets[name] = _createPreset(name); } return DialogBuilder.fromConfig(_presets[name]!); } }
建造者模式 vs 工厂模式
特性 | 建造者模式 | 工厂模式 |
---|---|---|
主要目的 | 分步构建复杂对象 | 创建对象家族 |
构建过程 | 显式控制每个步骤 | 隐藏创建细节 |
适用场景 | 包含多个组件的对象 | 不同系列的对象 |
Flutter应用 | 复杂组件配置、响应式布局 | 主题系统、平台适配 |
建造者模式的强大变体
1. 阶段式建造者
abstract class DialogBuilderPhase1 {
DialogBuilderPhase2 setTitle(String title);
}
abstract class DialogBuilderPhase2 {
DialogBuilderPhase3 setContent(String content);
}
class DialogBuilder implements
DialogBuilderPhase1,
DialogBuilderPhase2 {
// 分阶段实现...
}
// 强制按顺序调用:
DialogBuilder()
.setTitle('标题') // 必须第一步
.setContent('内容') // 必须第二步
.build();
2. 装饰器增强建造者
class DialogDecorator implements DialogBuilder {
final DialogBuilder _builder;
DialogDecorator(this._builder);
DialogBuilder title(String title) {
_builder.title(title);
return this;
}
// 添加额外功能
DialogDecorator withAnimation(Duration duration) {
// 添加动画逻辑
return this;
}
}
// 使用增强功能
DialogDecorator(CustomDialogBuilder())
.title('动画对话框')
.withAnimation(Duration(seconds: 1))
.build();
总结:建造者模式是你的UI组装线
- 核心价值: 将复杂对象的构建过程分解为可管理的步骤
- Flutter优势:
- 解决"参数爆炸"问题
- 创建不可变对象的灵活方式
- 提高大型组件配置的可读性
- 支持流畅的链式调用
- 适用场景: 复杂对话框、表单构建、响应式布局、主题配置
🔧 设计启示: 当组件参数超过5个或创建逻辑复杂时,建造者模式能显著改善代码质量!