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,一经查实,立即删除!

相关文章

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

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

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

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

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

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

[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…

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

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

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

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

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

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

Python 使用 OpenCV 将 MP4 转换为 GIF图

以下是使用 Python 和 OpenCV 将 MP4 转换为 GIF 的示例代码: 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库生成;

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

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

SpringBoot(9)-Dubbo+Zookeeper

目录 一、了解分布式系统 二、RPC 三、Dubbo 四、SpringBootDubboZookeeper 4.1 框架搭建 4.2 实现RPC 一、了解分布式系统 分布式系统:由一组通过网络进行通信,为了完成共同的任务而协调工作的计算机节点组成的系统 二、RPC RPC:远程…

【Github】如何使用Git将本地项目上传到Github

【Github】如何使用Git将本地项目上传到Github 写在最前面1. 注册Github账号2. 安装Git工具配置用户名和邮箱仅为当前项目配置(可选) 3. 创建Github仓库4. 获取仓库地址5. 本地操作(1)进入项目文件夹(2)克隆…

Spring:Spring整合Mybatis开发之纯Mybatis开发

目前我们已经对Spring有一个简单的认识了: Spring有一个容器,叫做IoC容器,里面保存bean。 在进行企业级开发的时候,其实除了将自己写的类让Spring管理之外,还有一部分重要的工作就是使用第三方的技术。前面已经讲了如何…

大语言模型---LoRA中损失值的计算

文章目录 概要损失计算流程小结 概要 Llama-7B模型的LoRA微调训练中,通过使用Cross-Entropy Loss来度量模型输出的预测分布和真实标签分布之间的距离,来衡量模型的准确性。 本文主要介绍LoRA中损失值的计算流程。 Cross-Entropy Loss作用:是…

如何选择服务器

如何选择服务器 选择服务器时应考虑以下几个关键因素: 性能需求。根据网站的预期流量和负载情况,选择合适的处理器、内存和存储容量。考虑网站是否需要处理大量动态内容或高分辨率媒体文件。 可扩展性。选择一个可以轻松扩展的服务器架构,以便…

IT资产管理工具-NetBox

IT资产管理工具-NetBox 推荐一款IT资产管理工具 了解推荐阅读官方中文文档 https://docs.wangluohe.com/introduction/ 硬件要求 ​ - 建议4Core 8G以上,100G存储空间 这里我使用的Linux镜像为 CentOS8-Stream 提前关闭Selinux和防火墙 部署NetBox 一&#…

实战 | C#中使用YoloV8和OpenCvSharp实现目标检测 (步骤 + 源码)

导 读 本文主要介绍在C#中使用YoloV8实现目标检测,并给详细步骤和代码。 详细步骤 【1】环境和依赖项。 需先安装VS2022最新版,.NetFramework8.0,然后新建项目,nuget安装 YoloSharp,YoloSharp介绍: https://github.com/dme-compunet/YoloSharp 最新版6.0.1,本文…

Java基于Spring Boot框架的房屋租赁系统,附源码

博主介绍:✌Java老徐、7年大厂程序员经历。全网粉丝12w、csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ 🍅文末获取源码联系🍅 👇🏻 精彩专栏推荐订阅👇&…

C语言:深入理解指针

一.内存和地址 我们知道计算机上CPU(中央处理器)在处理数据的时候,需要的数据是在内存中读取的,处理后的数据也会放回内存中,那我们买电脑的时候,电脑上内存是 8GB/16GB/32GB 等,那这些内存空间…