想要动态创建不同风格的按钮?想一键切换整个主题?工厂模式就是你的"生产流水线"!
想象一下这个场景:
你决定扩大奶茶店业务,推出两个品牌系列:
- 经典系列:传统珍珠奶茶,红白配色
- 清新系列:水果茶,蓝绿配色
每个系列都有自己风格的:
- 杯子设计
- 吸管样式
- 包装袋
- 会员卡
问题来了: 当顾客点单时,你如何确保:
- 经典系列的奶茶配经典杯+经典吸管+经典包装?
- 清新系列的水果茶配清新杯+清新吸管+清新包装?
- 避免经典杯配清新吸管这种"混搭事故"?
解决方案:建立两个专属工厂:
- 经典工厂:专门生产经典杯、经典吸管、经典包装
- 清新工厂:专门生产清新杯、清新吸管、清新包装
当顾客选择系列后,你只需告诉对应的工厂:"给我一套装备!"工厂就会返回风格一致的全套产品。
在Flutter中,这就是"抽象工厂模式"!而"工厂方法模式"则是它的灵活简化版。
先理解基础:工厂方法模式 (Factory Method)
核心思想: 定义一个创建对象的接口,但让子类决定实例化哪个类。
Flutter场景: 根据条件创建不同类型的按钮
// 按钮产品接口
abstract class AppButton {
Widget render(String text, VoidCallback onPressed);
}
// 具体产品1:圆角按钮
class RoundedButton implements AppButton {
Widget render(String text, VoidCallback onPressed) {
return ElevatedButton(
style: ElevatedButton.styleFrom(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(20),
),
onPressed: onPressed,
child: Text(text),
);
}
}
// 具体产品2:方形按钮
class SquareButton implements AppButton {
Widget render(String text, VoidCallback onPressed) {
return ElevatedButton(
style: ElevatedButton.styleFrom(
shape: const RoundedRectangleBorder(),
),
onPressed: onPressed,
child: Text(text),
);
}
}
// 工厂方法 - 根据主题创建按钮
class ButtonFactory {
static AppButton createButton(ThemeType theme) {
switch (theme) {
case ThemeType.rounded:
return RoundedButton();
case ThemeType.square:
return SquareButton();
default:
return RoundedButton();
}
}
}
// 使用示例:
final button = ButtonFactory.createButton(currentTheme);
button.render('确认', () => print('Clicked'));
优势:
- 将对象创建和使用分离
- 新增按钮类型时只需扩展工厂,不修改客户端代码
- 统一创建接口
进阶:抽象工厂模式 (Abstract Factory)
核心思想: 提供一个接口,用于创建相关或依赖对象的家族,而不需要指定具体类。
Flutter场景: 创建整套UI主题组件
// 抽象工厂 - 能生产全套UI组件
abstract class ThemeFactory {
AppButton createButton();
AppCard createCard();
AppTextField createTextField();
}
// 具体工厂1:生产经典主题组件
class ClassicThemeFactory implements ThemeFactory {
AppButton createButton() => ClassicButton();
AppCard createCard() => ClassicCard();
AppTextField createTextField() => ClassicTextField();
}
// 具体工厂2:生产清新主题组件
class FreshThemeFactory implements ThemeFactory {
AppButton createButton() => FreshButton();
AppCard createCard() => FreshCard();
AppTextField createTextField() => FreshTextField();
}
// 组件产品接口
abstract class AppButton {
Widget render(String text);
}
abstract class AppCard {
Widget render(Widget child);
}
abstract class AppTextField {
Widget render(String hint);
}
// 具体产品实现(以经典系列为例)
class ClassicButton implements AppButton {
Widget render(String text) => ElevatedButton(
style: ElevatedButton.styleFrom(primary: Colors.red),
onPressed: () {},
child: Text(text),
);
}
class ClassicCard implements AppCard {
Widget render(Widget child) => Card(
color: Colors.red[100],
child: child,
);
}
class ClassicTextField implements AppTextField {
Widget render(String hint) => TextField(
decoration: InputDecoration(
hintText: hint,
border: const OutlineInputBorder(),
),
);
}
// 清新系列产品实现类似...
使用抽象工厂:
class ThemeSwitcher extends StatelessWidget {
final ThemeFactory factory;
const ThemeSwitcher({required this.factory});
Widget build(BuildContext context) {
return Column(
children: [
factory.createButton().render('提交'),
const SizedBox(height: 20),
factory.createCard().render(
factory.createTextField().render('请输入')
),
],
);
}
}
// 在应用中使用
ThemeSwitcher(factory: ClassicThemeFactory()), // 经典主题
// 或
ThemeSwitcher(factory: FreshThemeFactory()), // 清新主题
优势:
- 确保组件风格一致性(所有组件来自同一工厂)
- 切换主题只需更换工厂对象
- 新增主题系列不影响现有代码
- 产品创建细节对客户端隐藏
Flutter中的实际应用
- 主题管理系统
// 创建主题工厂
final factory = isDarkMode ? DarkThemeFactory() : LightThemeFactory();
// 使用主题组件
return factory.createCard().render(
Column(
children: [
factory.createTextField().render('用户名'),
factory.createButton().render('登录'),
],
)
);
- 平台适配组件
abstract class PlatformWidgetsFactory {
AppBar createAppBar(String title);
Button createButton(String text);
}
class MaterialWidgetsFactory implements PlatformWidgetsFactory {
AppBar createAppBar(String title) => AppBar(title: Text(title));
Button createButton(String text) => ElevatedButton(...);
}
class CupertinoWidgetsFactory implements PlatformWidgetsFactory {
AppBar createAppBar(String title) => CupertinoNavigationBar(middle: Text(title));
Button createButton(String text) => CupertinoButton(...);
}
// 使用时
final factory = Platform.isIOS
? CupertinoWidgetsFactory()
: MaterialWidgetsFactory();
return Scaffold(
appBar: factory.createAppBar('首页'),
body: factory.createButton('点击我'),
);
- 复杂对话框构建
abstract class DialogFactory {
Widget createTitle(String text);
Widget createContent(String text);
Widget createActions(List<ActionItem> items);
}
class AlertDialogFactory implements DialogFactory { ... }
class BottomSheetDialogFactory implements DialogFactory { ... }
class FullscreenDialogFactory implements DialogFactory { ... }
工厂模式 vs 抽象工厂模式
特性 | 工厂方法模式 | 抽象工厂模式 |
---|---|---|
创建对象 | 单个产品 | 产品家族 |
主要目的 | 类延迟实例化到子类 | 创建相关对象组 |
扩展性 | 添加新产品需修改工厂 | 添加新系列只需新工厂 |
Flutter典型应用 | 条件创建单一组件 | 主题系统/平台适配 |
最佳实践指南
何时使用工厂方法:
- 需要创建单一类型对象
- 创建过程需要封装
- 需要运行时决定对象类型
- 示例:根据用户类型创建不同的个人主页
何时使用抽象工厂:
- 需要创建多个相关对象
- 需要确保产品兼容性
- 需要支持多套产品系列
- 示例:主题系统、平台适配、A/B测试UI方案
工厂模式优势:
- ✅ 解耦创建和使用
- ✅ 符合开闭原则(扩展开放,修改关闭)
- ✅ 简化复杂对象创建
- ✅ 提高代码可测试性
需要注意:
- 避免过度设计简单场景
- 工厂类可能成为"上帝对象"
- 新增产品类型可能需修改工厂接口
总结:工厂模式是你的UI流水线
- 工厂方法:你的"专属定制工坊" - 根据需求生产特定类型产品
- 抽象工厂:你的"主题生产线" - 一键产出风格一致的全套产品
- 核心价值:创建逻辑和使用解耦,支持灵活扩展
- Flutter应用:主题系统、平台适配、动态UI生成
💡 设计启示: 当你发现代码中有大量条件判断创建不同对象时,就是工厂模式的用武之地!