想要动态创建不同风格的按钮?想一键切换整个主题?工厂模式就是你的"生产流水线"!


想象一下这个场景:

你决定扩大奶茶店业务,推出两个品牌系列:

  1. 经典系列:传统珍珠奶茶,红白配色
  2. 清新系列:水果茶,蓝绿配色

每个系列都有自己风格的:

  • 杯子设计
  • 吸管样式
  • 包装袋
  • 会员卡

问题来了: 当顾客点单时,你如何确保:

  1. 经典系列的奶茶配经典杯+经典吸管+经典包装?
  2. 清新系列的水果茶配清新杯+清新吸管+清新包装?
  3. 避免经典杯配清新吸管这种"混搭事故"?

解决方案:建立两个专属工厂:

  • 经典工厂:专门生产经典杯、经典吸管、经典包装
  • 清新工厂:专门生产清新杯、清新吸管、清新包装

当顾客选择系列后,你只需告诉对应的工厂:"给我一套装备!"工厂就会返回风格一致的全套产品

在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()),  // 清新主题

优势:

  1. 确保组件风格一致性(所有组件来自同一工厂)
  2. 切换主题只需更换工厂对象
  3. 新增主题系列不影响现有代码
  4. 产品创建细节对客户端隐藏

Flutter中的实际应用

  1. 主题管理系统
// 创建主题工厂
final factory = isDarkMode ? DarkThemeFactory() : LightThemeFactory();// 使用主题组件
return factory.createCard().render(Column(children: [factory.createTextField().render('用户名'),factory.createButton().render('登录'),],)
);
  1. 平台适配组件
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('点击我'),
);
  1. 复杂对话框构建
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典型应用条件创建单一组件主题系统/平台适配

最佳实践指南

  1. 何时使用工厂方法:

    • 需要创建单一类型对象
    • 创建过程需要封装
    • 需要运行时决定对象类型
    • 示例:根据用户类型创建不同的个人主页
  2. 何时使用抽象工厂:

    • 需要创建多个相关对象
    • 需要确保产品兼容性
    • 需要支持多套产品系列
    • 示例:主题系统、平台适配、A/B测试UI方案
  3. 工厂模式优势:

    • ✅ 解耦创建和使用
    • ✅ 符合开闭原则(扩展开放,修改关闭)
    • ✅ 简化复杂对象创建
    • ✅ 提高代码可测试性
  4. 需要注意:

    • 避免过度设计简单场景
    • 工厂类可能成为"上帝对象"
    • 新增产品类型可能需修改工厂接口

总结:工厂模式是你的UI流水线

  • 工厂方法:你的"专属定制工坊" - 根据需求生产特定类型产品
  • 抽象工厂:你的"主题生产线" - 一键产出风格一致的全套产品
  • 核心价值:创建逻辑和使用解耦,支持灵活扩展
  • Flutter应用:主题系统、平台适配、动态UI生成

💡 设计启示: 当你发现代码中有大量条件判断创建不同对象时,就是工厂模式的用武之地!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/web/86907.shtml
繁体地址,请注明出处:http://hk.pswp.cn/web/86907.shtml
英文地址,请注明出处:http://en.pswp.cn/web/86907.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

基于 SpringBoot+Vue.js+ElementUI 的 Cosplay 论坛设计与实现7000字论文

基于 SpringBootVue.jsElementUI 的 Cosplay 论坛设计与实现 摘要 本论文设计并实现了一个基于 SpringBoot、Vue.js 和 ElementUI 的 Cosplay 论坛平台。该平台旨在为 Cosplay 爱好者提供一个集作品展示、交流互动、活动组织于一体的综合性社区。论文首先分析了 Cosplay 论坛…

超标量处理器11-Alpha21264 处理器

1. 简介 21264处理器是一款4-way&#xff0c;乱序执行的超标量处理器&#xff0c;采用0.35um的CMOS工艺&#xff0c;工作电压是2.2V, 工作频率是466-667MHz; 处理器能支持60条指令&#xff0c;也即ROB的深度是60; Load/Store指令也采取乱序执行, 总共7级流水。I-CACHE和D-CACH…

Spring 中 Bean 的生命周期

一、什么是 Bean 生命周期&#xff1f; Spring 中的 Bean 生命周期是指一个 Bean 从 被容器创建到 最终销毁 所经历的一系列过程。 它体现了 Spring IOC 容器在管理 Bean 实例时所执行的各个钩子流程&#xff0c;包括初始化、依赖注入、增强处理、销毁等多个环节。 二、Bean 生…

C++ 中 std::string 与 QString 的深度剖析

在 C 编程领域&#xff0c;std::string 和 QString 是两种广泛应用的字符串类型&#xff0c;它们在设计理念、功能特性以及适用场景上都呈现出鲜明的特点。本文将从多个维度对这两种字符串类型进行深度剖析&#xff0c;并详细阐述它们之间的相互转化方法。 std::string 是 C 标…

不止于“修补”:我如何用Adobe AI重塑设计与视频叙事流程

最近我深度体验了一把来自英国Parvis School of Economics and Music的Adobe正版教育订阅&#xff0c;在把玩PhotoShop、Premiere Pro这些“老伙计”的新功能时&#xff0c;的确挖到了一些宝藏&#xff0c;觉得非常有必要与大家说道说道。首先得聊聊这个订阅给我的直观感受&…

重头开始学ROS(5)---阿克曼底盘的URDF建模与Gazebo控制(使用Xacro优化)

阿克曼底盘的URDF建模与Gazebo控制&#xff08;使用Xacro优化&#xff09; 阿克曼底盘建模 建模 我们使用后轮驱动&#xff0c;前轮转向的阿克曼底盘模型。 那么对于后轮只需进行正常的continous joint连接即可 对于前轮&#xff0c;有两个自由度&#xff0c;旋转和转向&…

RabbitMq中启用NIO

✅ 所属类 com.rabbitmq.client.ConnectionFactory&#x1f9e0; 使用背景 RabbitMQ Java 客户端默认使用传统的 阻塞 I/O (java.net.Socket) 实现。如果你希望&#xff1a; 更好地控制 线程数获得更好的 并发性能降低 每个连接的线程占用在高并发连接或消费者数量较多的系统…

[Dify]-基础篇2- 如何注册并快速上手 Dify 平台

在生成式 AI 应用开发新时代,如何快速搭建一个高效、可维护、易上线的 AI 工具,是每位开发者关注的核心。Dify,正是为此而生的一站式平台。本篇将以新手视角,带你从注册账号、配置环境,到构建应用、部署上线,手把手完成你的第一个 AI 项目。 注册并设置工作环境 1. 账号…

Java面试宝典:基础七

153. 如何实现对象克隆? 答: 对象克隆有两种主要方式: 浅克隆:实现Cloneable接口并重写Object.clone() class Person implements Cloneable {String name;Car car; // 引用类型@Override

spring-security原理与应用系列:requestMatchers和authorizeRequests

目录 简单示例 WebSecurityConfig requestMatchers ​​​​​​​requestMatchers ​​​​​​​antMatchers ​​​​​​​chainRequestMatchers ​​​​​​​setMatchers ​​​​​​​requestMatcher ​​​​​​​WebSecurity ​​​​​​​performBuild…

Bessel位势方程求解步骤

问题 考虑偏微分方程&#xff08;PDE&#xff09;&#xff1a; − Δ u u f , x ∈ R n , -\Delta u u f, \quad x \in \mathbb{R}^n, −Δuuf,x∈Rn, 其中 f ∈ L 2 ( R n ) f \in L^2(\mathbb{R}^n) f∈L2(Rn)。这是一个线性椭圆型方程&#xff0c;称为 Bessel 位势方…

if __name__ == ‘__main__‘:

基本概念 if __name__ __main__: 是一个条件判断语句&#xff0c;用于确定当前模块是作为主程序运行&#xff0c;还是被其他模块导入。 __name__ 变量 __name__ 是Python的一个内置变量&#xff0c;表示当前模块的名称当一个模块被直接运行时&#xff0c;__name__ 的值会被…

浅谈Apache HttpClient的相关配置和使用

Apache HttpClient是由Apache软件基金会维护的一款开源HTTP客户端库&#xff0c;对比最基础的 HttpURLConnection 而言,它的优势时支持连接池管理&#xff0c;拦截器&#xff08;Interceptor&#xff09;机制&#xff0c;同步/异步请求支持等能力。 在使用这个组件时&#xff…

【Teensy】在ArduinoIDE中配置Teensy4.1

1.文件——首选项 在其他开发板管理器地址这里添加&#xff1a; https://www.pjrc.com/teensy/package_teensy_index.json 点击确定&#xff01; 2.安装Teensy(for Arduino IDE…) 按照图中1&#xff0c;2&#xff0c;3操作&#xff01;可以选择上一个版本&#xff08;不使用最…

企业自建云概念解读|私有云、专有云、混合云、分布式云、企业云

随着云计算技术逐渐成熟&#xff0c;越来越多的企业开始在本地数据中心自行搭建云平台&#xff0c;满足数据合规、业务性能与连续性、节约成本等多方面的需求。不过&#xff0c;面对多种多样的自建云产品&#xff0c;不少用户会有类似的疑问&#xff1a;自建云等于私有云吗&…

反弹 Shell 升级为全交互终端的两种高效方法

目录 🚀 升级反弹 Shell 为全交互终端:两种高效方法 🛠️ 方法 1:利用 Python pty.spawn 创建伪终端 📋 操作步骤

Hyper-YOLO: When Visual Object Detection Meets Hypergraph Computation论文精读(逐段解析)

Hyper-YOLO: When Visual Object Detection Meets Hypergraph Computation论文精读&#xff08;逐段解析&#xff09; 论文地址&#xff1a;https://arxiv.org/abs/2408.04804 CVPR 2024 Yifan Feng, Jiangang Huang, Shaoyi Du, Senior Member, IEEE, Shihui Ying, Jun-Hai Y…

Windows 下配置多个 GitHub 账号的 SSH Key

Windows 下配置多个 GitHub 账号的 SSH Key 假设你有以下两个 SSH key 文件&#xff1a; 第一个账号&#xff1a;id_rsa&#xff08;默认&#xff09;第二个账号&#xff1a;id_rsa_github ✅ 步骤&#xff1a;在 Windows 上配置多个 GitHub 账号 SSH Key 1️⃣ 打开 SSH 配…

技术选型:时序数据库(三)

IoTDB vs InfluxDB vs TDengine 时序数据库横评对比。 从 架构设计、性能、功能、生态、适用场景 等维度&#xff0c;对三款时序数据库进行深度对比&#xff0c;助您精准选型。 一、核心架构对比 数据库 存储模型 数据模型 扩展性 Apache IoTDB 分层存储&#xff08;TsFi…

电子电路原理第十九章(非线性运算放大器电路的应用)

单片集成运算放大器价格便宜、用途广泛且性能可靠。它们不仅可以用于线性电路,如电压放大器、电流源和有源滤波器,而且可以用于非线性电路,如比较器、波形生成器和有源二极管电路。非线性运放电路的输出通常与输入信号的波形不同,这是因为运放在输入周期的某个时间段内达到…