Flutter 设计模式全面解析:抽象工厂


设计模式作为软件开发中的经典解决方案,在 Flutter 的开发中也能为我们提供强大的架构支持。本文来介绍一下如何在 Flutter 中来实现抽象工厂设计模式,以及如何创建一系列相关或依赖对象并优雅地管理它们之间的复杂依赖关系。

日常开发中我们也能经常看到 Flutter 中运用抽象工厂的身影。比如,当需要针对不同操作系统(如 iOSAndroid )设计不同风格的按钮和文本框时,使用抽象工厂模式可以确保组件风格的一致性,同时大幅降低代码耦合度,抽象工厂模式非常适合构建跨平台的UI框架。还有在数据提供层,利用抽象工厂设计模式可以用于灵活管理多种数据提供的方案,例如有网络请求 REST APIShared preferences或者 Data base,主工程通过构建不同的工厂来获取数据。接下来,我们将以实际代码的示例,深入解析这种模式的结构和应用场景。

什么是抽象工厂

网上搜索后是这么介绍它的,抽象工厂模式(Abstract Factory Pattern)是一种创建型设计模式,它提供一个接口来创建一系列相关或依赖的对象,而无需指定具体的实现类。主要目的是将创建对象系列封装在单独的工厂对象中,从而抽象对象创建过程。对于所有支持的对象系列,定义一个用于创建对象系列的通用接口,然后创建一个具体的工厂类来实现该接口。

参考上图,举个例子来说明一下,假设你有一家具公司,家具公司需要提供不同风格的家具套装(如现代风格、欧式风格)。每个套装包括沙发、桌子和椅子。为了便于扩展新的风格家具或修改现有产品,用抽象工厂模式实现家具的动态组合,其代码实现如下:

// 1 产品接口:沙发
abstract class Sofa { void describe(); }
// 2 产品接口:桌子
abstract class Table { void describe(); }
// 3 产品接口:椅子
abstract class Chair { void describe(); }// 4 抽象工厂:家具工厂
abstract class FurnitureFactory {Sofa createSofa();Table createTable();Chair createChair();
}

上面位置1、2、3的代码是为每件产品明确声明接口 (沙发、桌子或椅子)。 然后,确保所有产品变体都继承这些接口。例如,所有风格的椅子都实现椅子接口;所有风格的桌子都实现桌子接口,以此类推。

接下来,位置4代码声明抽象工厂,包含所有产品构造方法的接口。 例如 createSofa 创建沙发 、createTable 创建桌子和 createChair 创建椅子。 并且这些方法必须返回抽象产品类型, 即上面抽取的那些接口: 沙发、桌子和椅子等等。

然后再基于抽象工厂接口创建不同的工厂类。 每个工厂类都只能返回特定类别的产品, 例如,现代家具工厂 ModernFurnitureFactory 只能创建现代沙发 ModernSofa、现代桌子 ModernTable 和现代椅子 ModernChair 对象;同理,欧式家具工厂 EuropeanFurnitureFactory 只能创建欧式沙发 EuropeanSofaSofa 、 欧式桌子 EuropeanSofaTable 和欧式椅子 EuropeanSofaChair 对象。

下图中的代码是抽象产品接口的具体实现,包含了现代风格及欧式风格的沙发、桌子和椅子,

客户端代码实现:

void createFurniture(FurnitureFactory factory) {final sofa = factory.createSofa();final table = factory.createTable();final chair = factory.createChair();sofa.describe();table.describe();chair.describe();
}

这样一来,如果我们还想新增一套家具风格(如:美式风格家具)也非常简单,实现抽象的产品接口AmericanSofaAmericanTableAmericanChair,然后建一个美式风格家具的工厂类 AmericanFurnitureFactory 并返回具体的产品就可以了。

以下是调用并输出结果:

void main() {// 创建现代风格家具createFurniture(ModernFurnitureFactory());//  A modern style sofa//  A modern style table//  A modern style chair// 创建欧式风格家具createFurniture(EuropeanFurnitureFactory());// A European style sofa// A European style table// A European style chair
}

这种模式能确保套装风格的统一,同时又能方便扩展新风格的家具组合。在实际的应用场景中,即可以支持用户根据房间风格选择成套家具,又方便快速配置不同风格的房间布局,还可以提供模块化的家具搭配方案。

生活中能联想到类似的应用场景还有很多,如一家连锁快餐店提供不同风味的套餐(如亚洲风味、西式风味)。每个套餐包含主食、饮料和甜点。那么为了便于管理和扩展套餐,使用抽象工厂模式实现餐品的动态生成。

抽象工厂模式结构


上图是抽象工厂模式的结构结构示意图,可以看出,抽象工厂模式一般分为5个部分。

  • 抽象工厂:接口声明了一组创建各种抽象产品的方法。
  • 具体工厂:实现抽象工厂的构建方法。 每个具体工厂都对应特定产品变体, 且仅创建此种产品变体。
  • 抽象产品:构成系列产品的一组不同但相关的产品声明接口。
  • 具体产品:是抽象产品的多种不同类型实现。 所有变体 (欧式/现代) 都必须实现相应的抽象产品 (椅子/沙发)。
  • 客户端:仅使用抽象工厂和产品类声明的接口。

抽象工厂隐藏了对象的创建逻辑,提供了一个统一的入口点,能做到创建逻辑与使用逻辑解耦,这样,在调用的地方只需调用抽象工厂的接口,而不关心具体对象如何构建或组成。通过这种抽象,产品的创建方式、数据结构和表示方式可以独立变化,而不会影响高层模块的逻辑。还解决了不同产品族的一致性的问题,同一个工厂负责创建一个产品系列的所有对象,这就保证了系列中的产品能够正确地协同工作,避免了混用不同产品的问题。

与工厂模式的区别

抽象工厂模式和工厂方法模式都是创建型设计模式,抽象工厂模式处理的是产品族(多个相关产品),而工厂模式只处理的是单个产品的创建,也就是说可以将工厂方法设计模式视为抽象工厂模式的一个子集,即抽象工厂由几种工厂方法组成,其中每种方法仅创建一个特定对象。

项目中的应用

除了上面说到的例子,在项目开发过程中,也会大量的用到抽象工厂模式。尤其是对于 Flutter 做跨平台的开发来说,是非常合适的应用场景,比如当我们需要同时适配 MacWindow 风格的 Widget 时,可以做以下操作:

定义抽象产品

// 抽象产品:按钮
abstract class Button {void render();
}// 抽象产品:文本框
abstract class TextBox {void render();
}

定义具体产品

// Windows 风格按钮
class WindowsButton implements Button {void render() { print("Rendering a Windows button"); }
}// Windows 风格文本框
class WindowsTextBox implements TextBox {void render() { print("Rendering a Windows text box"); }
}// MacOS 风格按钮
class MacButton implements Button {void render() { print("Rendering a MacOS button"); }
}// MacOS 风格文本框
class MacTextBox implements TextBox {void render() { print("Rendering a MacOS text box"); }
}

定义抽象工厂

abstract class UIFactory {Button createButton();TextBox createTextBox();
}

定义具体工厂

class WindowsFactory implements UIFactory {Button createButton() => WindowsButton();TextBox createTextBox() => WindowsTextBox();
}class MacFactory implements UIFactory {Button createButton() => MacButton();TextBox createTextBox() => MacTextBox();
}

客户端及调用代码:

void renderUI(UIFactory factory) {final button = factory.createButton();final textBox = factory.createTextBox();button.render();textBox.render();
}void main() {// 使用 Windows 工厂print("Rendering Windows UI:");renderUI(WindowsFactory());// 使用 MacOS 工厂print("\nRendering MacOS UI:");renderUI(MacFactory());
}

小结

抽象工厂模式的应用非常广泛,包括文章开头提到在数据提供层的设计中也会用到它,其作用就是提供一个接口来创建一系列相关或依赖的对象,是创建和管理多个对象的优雅且高效的解决方案,合理的使用有利于代码拓展,减少因产品族不一致带来的问题。但抽象工厂也并非万能,如果用在对单一产品的灵活扩展或者简单需求场景,那就有点儿显得过于笨重。因此,在使用此模式时,我们还是需要根据项目的实际需求进行权衡。

同时,任何设计模式的使用并是非硬性的框架约束,而是开发者应对复杂性和变化的一种工具。理解模式背后的设计思想,并将其灵活运用到项目中,才是提升代码质量的关键。也希望本篇能够帮到你,感谢您的阅读。

参考资料
抽象工厂模式
Flutter Design Patterns: 11 — Abstract Factory

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

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

相关文章

AWS IAM 及其功能

IAM 代表身份和访问管理,可帮助控制谁可以进入云、访问 AWS 资源以及进入后可以做什么。 身份: IAM 帮助管理可以与 AWS 资源交互的身份(如用户名或服务帐户)。 访问:它决定每个身份可以在 AWS 服务上执行哪些操作&am…

SpringBoot集成Minio实现上传凭证、分片上传、秒传和断点续传

总体概述 Spring Boot整合Minio后,前端的文件上传有两种方式: 1.文件上传到后端,由后端保存到Minio 这种方式好处是完全由后端集中管理,可以很好的做到、身份验证、权限控制、文件与处理等,并且可以做一些额外的业务逻…

『 Linux 』网络层 - IP协议 (二)

文章目录 路由NAT技术分片与组装分片的组装IP协议分片的短板 路由 通常情况路由器具备了一个非常重要的功能,即构建子网; 同时路由器需要实现跨网络通信,说明路由器必须存在两个或以上的IP地址,通常在路由器中可以看到几个接口,分别是一个WAN口和几个LAN口; WAN口IP被称为公网I…

深度学习实战图像缺陷修复

这里写目录标题 概述1. 图像缺陷修复的研究背景2. 传统图像缺陷修复方法的局限性(1) 基于纹理合成的方法(2) 基于偏微分方程(PDE)的方法 3. 深度学习在图像缺陷修复中的兴起(1) 深度学习的基本思路(2) 深度学习方法的优势(3) 关键技术的引入 4. 深度学习…

vue从入门到精通(七):事件处理

1,事件的基本使用 1.使用v-on:xxx或 xxx 绑定事件,其中xxx是事件名2.事件的回调需要配置在methods对象中,最终会在vm上3.methods中配置的所数,不要用箭头函数!否则this就不是vm了4.methods中配置的函数,都是被Vue所管…

如何在 .gitignore 中仅保留特定文件:以忽略文件夹中的所有文件为例

在日常的开发工作中,使用 Git 来管理项目是不可或缺的一部分。项目中的某些文件夹可能包含大量的临时文件、生成文件或不需要版本控制的文件。在这种情况下,我们通常会使用 .gitignore 文件来忽略这些文件夹。然而,有时我们可能希望在忽略整个…

【SQL实验】索引操作(菜单操作和命令操作)

【代码是自己的解答,并非标准答案,也有可能写错,文中可能会有不准确或待完善之处,恳请各位读者不吝批评指正,共同促进学习交流】 文件”成绩管理”导入【具体操作前几篇文章详细展示过来,这里跳过。还是不太…

MVC 模型:架构与原理

MVC 模型:架构与原理 MVC(Model-View-Controller)模型是一种广泛应用于软件工程的架构模式,主要用于分离应用程序的逻辑层,以提高其可维护性和可扩展性。MVC模型将应用程序分为三个核心组件:模型(Model)、视图(View)和控制器(Controller)。本文将深入探讨MVC模型的…

[pdf,epub]162页《分析模式》漫谈合集01-35提供下载

《分析模式》漫谈合集01-35的pdf、epub文件,已上传至本号的CSDN资源。 如果CSDN资源下载有问题,可到umlchina.com/url/ap.html。 已排版成适合手机阅读,pdf的排版更好一些。 ★UMLChina为什么叒要翻译《分析模式》? ★[缝合故事…

【Linux学习】【Ubuntu入门】1-7 ubuntu下磁盘管理

1.准备一个U盘或者SD卡(插上读卡器),将U盘插入主机电脑,右键点击属性,查看U盘的文件系统确保是FAT32格式 2.右键单击ubuntu右下角图标,将U盘与虚拟机连接 参考链接 3. Ubuntu磁盘文件:/dev/s…

Leetcode152. 乘积最大子数组(HOT100)

链接 代码&#xff1a; class Solution { public:int maxProduct(vector<int>& nums) {int f nums[0],g nums[0];int res nums[0];for(int i 1;i<nums.size();i){//int i 1 not int i 0 ,因为我们已经初始化好了首元素作为子数组的最大值和最小值int a n…

移远通信推出全新5G RedCap模组RG255AA系列,以更高性价比加速5G轻量化大规模商用

11月20&#xff0c;全球领先的物联网整体解决方案供应商移远通信宣布&#xff0c;正式推出其全新5G RedCap模组RG255AA系列。该系列模组支持5G NR独立组网&#xff08;SA&#xff09;和LTE Cat 4双模通信&#xff0c;具有高性能高集成度、低功耗、小尺寸、高性价比等优势&#…

【CVE-2024-9413】SCP-Firmware漏洞:安全通告

安全之安全(security)博客目录导读 目录 一、概述 二、修订历史 三、CVE根因分析 四、问题修复解决 一、概述 在SCP固件中发现了一个漏洞,如果利用该漏洞,可能会允许应用处理器(AP)在系统控制处理器(SCP)固件中导致缓冲区溢出。 CVE IDCVE-2024-9413受影响的产品SC…

数据集-目标检测系列- 花卉 玫瑰 检测数据集 rose >> DataBall

数据集-目标检测系列- 花卉 玫瑰 检测数据集 rose >> DataBall DataBall 助力快速掌握数据集的信息和使用方式&#xff0c;会员享有 百种数据集&#xff0c;持续增加中。 贵在坚持&#xff01; 数据样例项目地址&#xff1a; * 相关项目 1&#xff09;数据集可视化项…

详解Qt QTimeZone 时区类

文章目录 QTimeZone 详解前言什么是 QTimeZone&#xff1f;QTimeZone 的构造函数和常用成员函数构造函数1. 默认构造函数2. 指定时区 ID 构造函数3. 根据 UTC 偏移量构造 常用成员函数1. 获取时区 IDid 2. 检查时区是否有效isValid 3. 获取 UTC 偏移量offsetFromUtc 4. 检查是否…

Linux应用编程(C语言编译过程)

目录 1. 举例 2.预处理 2.1 预处理命令 2.2 .i文件内容解读 3.编译 4.汇编 5.链接 5.1 链接方式 5.1.1 静态链接 5.1.2 动态链接 5.1.3 混合链接 1. 举例 Linux的C语言开发&#xff0c;一般选择GCC工具链进行编译&#xff0c;通过下面的例子来演示GCC如何使用&#…

GitHub 开源项目 Puter :云端互联操作系统

每天面对着各种云盘和在线应用&#xff0c;我们常常会遇到这样的困扰。 文件分散在不同平台很难统一管理&#xff0c;付费订阅的软件越来越多&#xff0c;更不用说那些烦人的存储空间限制了。 最近在 GitHub 上发现的一个开源项目 Puter 彻底改变了我的在线办公方式。 让人惊…

Python 使用 OpenCV 将 MP4 转换为 GIF图

以下是使用 Python 和 OpenCV 将 MP4 转换为 GIF 的示例代码&#xff1a; python import cv2 import imageiodef mp4_to_gif(mp4_path, gif_path, fps10, start_timeNone, end_timeNone):"""将MP4视频转换为GIF动图。:param mp4_path: 输入MP4视频的路径。:pa…

el-table的树形结构后端返回的id没有唯一键怎么办

前端自己生成唯一键 首先尝试了表格的几个字段用-拼接成唯一键 但是仍报错 只好自己利用uuid库生成&#xff1b;

【Linux】缓冲区/磁盘inode/动静态库

目录 一、缓冲区 &#xff08;一&#xff09;概念 &#xff08;二&#xff09;刷新策略 &#xff08;三&#xff09;仿写FILE &#xff08;四&#xff09;内核缓冲区 二、磁盘 &#xff08;一&#xff09;磁盘的存储 &#xff08;二&#xff09;磁盘的抽象存储结构 &am…