23种设计模式的Flutter实现第一篇创建型模式(一)

目录

一、设计模式的分类

1.创建型模式

2.结构型模式

3.行为型模式

二、使用Flutter实现创建型设计模式

1.单例模式(Singleton)

1.概念

2.实现步骤

1.使用Dart的工厂构造函数

2.示例代码

3.使用单例模式

4.异步实现方式

2.工厂方法模式(Factory Method)

 1.概念

2.实现步骤        

1.定义日志记录器的抽象接口

2.定义具体的日志记录器

3.创建日志记录器的工厂类

4.使用工厂方法创建日志记录器

3.抽象工厂模式(Abstract Factory)

 1.概念

2.实现步骤

1.定义Alert抽象类

2.创建具体的Alert子类

3.创建AlertFactory工厂类

4.使用AlertFactory展示不同的Alert

4.建造者模式(Builder)

 1.概念

2.实现步骤

1.定义UserProfile类

2.创建UserProfileBuilder类

3.使用UserProfileBuilder创建UserProfile对象

5.原型模式(Prototype)

 1.概念

2.实现步骤

1.定义Shape抽象类

2.创建具体的Shape子类

3.使使用克隆创建新对象


        设计模式是软件开发中解决特定问题的通用解决方案。在代码中使用设计模式可以帮助我们更好地组织代码、提高复用性、增强扩展性。今天我们就来深入了解四人帮(GoF)提出的23种经典设计模式,这些模式被广泛应用于现代软件开发中,适合解决常见的设计难题。

一、设计模式的分类

        GOF把设计模式分成三大类,分别是创建型模式、结构性模式、行为型模式。

1.创建型模式

        创建型模式关注对象的实例化过程,通过封装实例化逻辑,使代码更灵活、解耦。

        创建型模式分为单例模式、工厂方法模式、抽象工厂模式、建造者模式、原型模式。

2.结构型模式

        结构型模式关注类和对象的组合,以实现更大的功能和灵活的结构。

        结构性模式分为适配器模式(Adapter)、桥接模式(Bridge)、组合模式(Composite)

、装饰器模式(Decorator)、 外观模式(Facade)、 享元模式(Flyweight)、 代理模式(Proxy)

3.行为型模式

        行为型模式关注对象间的交互和职责分配,提高对象之间的协作效率。

        行为型设计模式分为责任链模式(Chain of Responsibility)、命令模式(Command)、 解释器模式(Interpreter)、迭代器模式(Iterator)、中介者模式(Mediator)、 备忘录模式(Memento)、 观察者模式(Observer)、 状态模式(State)、 策略模式(Strategy)、 模板方法模式(Template Method)、 访问者模式(Visitor)

二、使用Flutter实现创建型设计模式

1.单例模式(Singleton)

1.概念

        在Flutter中,单例模式是一种常见的设计模式,可以确保一个类只有一个实例,且为全局共享。这对于需要全局管理的对象(如数据库连接、网络请求、状态管理等)非常有用。下面,我们就来实现一个典型的单例模式。

2.实现步骤

1.使用Dart的工厂构造函数

        在 Dart 中,我们可以通过 factory 构造函数来实现单例模式。factory 构造函数可以控制实例的创建,并确保只创建一个实例。

2.示例代码

        我们以 DatabaseService 类为例,假设它用于管理数据库连接。以下代码展示了如何实现单例模式:

class DatabaseService {// 私有的静态变量,存储唯一实例static final DatabaseService _instance = DatabaseService._internal();// 私有的命名构造函数,用于初始化实例DatabaseService._internal();// 工厂构造函数,用于返回唯一实例factory DatabaseService() {return _instance;}// 示例方法void connect() {print('Connecting to the database...');}
}
3.使用单例模式

        创建 DatabaseService 的实例时,无论调用多少次 DatabaseService(),都将返回相同的实例 _instance。

void main() {var db1 = DatabaseService();var db2 = DatabaseService();// 验证是否为相同实例if (identical(db1, db2)) {print('Both instances are identical.');}// 使用单例方法db1.connect();
}

        在上面的代码中,调用调用 DatabaseService() 将始终返回同一实例。

4.异步实现方式

        如果您的类需要异步初始化(例如网络请求或数据库初始化),可以使用 Future 返回一个 singleton 实例。

class DatabaseService {static DatabaseService? _instance;DatabaseService._internal();static Future<DatabaseService> getInstance() async {if (_instance == null) {_instance = DatabaseService._internal();// 模拟异步操作await Future.delayed(Duration(seconds: 1));print('Database initialized');}return _instance!;}
}

        使用异步单例:

void main() async {var db = await DatabaseService.getInstance();db.connect();
}

        这样,就实现了一个简单的单例模式。使用单例模式有助于在全局范围内共享实例,避免创建多个不必要的对象。

2.工厂方法模式(Factory Method)

 1.概念

        在Flutter中,工厂方法模式用于创建对象,同时将对象的创建逻辑与具体的实例分离。使用这种模式可以让客户端代码更灵活地处理不同类型的对象。下面是如何在Flutter中使用工厂方法模式的示例。

        我们以一个日志记录器为例,看一下工厂方法模式的实现步骤。

2.实现步骤        

        假设我们要实现一个日志记录器 Logger,可以根据不同的日志级别(如 Debug、Error)创建不同类型的日志对象。我们将使用工厂方法模式来创建这些不同的日志对象,而不直接暴露具体的类。

1.定义日志记录器的抽象接口

        首先,我们定义一个 Logger 抽象类,声明一个 log 方法。

abstract class Logger {void log(String message);
}
2.定义具体的日志记录器

        然后,我们创建几个实现 Logger 接口的具体日志记录器类,比如 DebugLogger 和 ErrorLogger。

class DebugLogger implements Logger {@overridevoid log(String message) {print('DEBUG: $message');}
}class ErrorLogger implements Logger {@overridevoid log(String message) {print('ERROR: $message');}
}
3.创建日志记录器的工厂类

        接下来,我们创建一个 LoggerFactory 类,用于根据不同的日志级别来返回对应的日志记录器。

enum LoggerType { debug, error }class LoggerFactory {// 工厂方法,根据 LoggerType 返回对应的 Logger 实例static Logger createLogger(LoggerType type) {switch (type) {case LoggerType.debug:return DebugLogger();case LoggerType.error:return ErrorLogger();default:throw Exception('Unsupported Logger Type');}}
}

        在 createLogger 工厂方法中,传入一个 LoggerType 枚举值,根据该值返回相应的日志记录器实例。

4.使用工厂方法创建日志记录器

        客户端代码可以使用 LoggerFactory 来创建不同的日志记录器,而无需直接实例化具体类:

void main() {Logger debugLogger = LoggerFactory.createLogger(LoggerType.debug);debugLogger.log('This is a debug message.');Logger errorLogger = LoggerFactory.createLogger(LoggerType.error);errorLogger.log('This is an error message.');
}

        在上面的例子中,LoggerFactory 类通过 createLogger 方法返回 Logger 的不同实现。客户端代码可以根据 LoggerType 创建不同的日志记录器,而不必知道每个记录器的具体实现细节。

3.抽象工厂模式(Abstract Factory)

 1.概念

        在Flutter中,工厂模式是一种非常有用的设计模式,可以用于在不暴露对象创建逻辑的前提下,根据条件创建和返回不同的对象。工厂模式与工厂方法模式略有不同,它更关注创建复杂对象,而不仅仅是通过继承来决定具体实例的生成。下面是如何在Flutter中使用工厂模式的示例。

        我们以一个消息提示框为例,看一下抽象工厂模式的实现。

2.实现步骤

        假设我们想要实现一个 AlertFactory 类,用于根据不同的需求来创建不同样式的提示框组件,例如:信息提示警告提示、和错误提示

1.定义Alert抽象类

        首先,我们定义一个 Alert 抽象类,该类声明了一个 showAlert 方法,用于展示提示框。

import 'package:flutter/material.dart';abstract class Alert {void showAlert(BuildContext context);
}
2.创建具体的Alert子类

        接下来,我们创建几个 Alert 的具体实现类,比如 InfoAlert、WarningAlert 和 ErrorAlert,它们各自定义了不同的提示框样式。

class InfoAlert implements Alert {@overridevoid showAlert(BuildContext context) {showDialog(context: context,builder: (context) => AlertDialog(title: Text('Info'),content: Text('This is an informational message.'),actions: [TextButton(onPressed: () => Navigator.pop(context),child: Text('OK'),),],),);}
}class WarningAlert implements Alert {@overridevoid showAlert(BuildContext context) {showDialog(context: context,builder: (context) => AlertDialog(title: Text('Warning'),content: Text('This is a warning message.'),actions: [TextButton(onPressed: () => Navigator.pop(context),child: Text('OK'),),],),);}
}class ErrorAlert implements Alert {@overridevoid showAlert(BuildContext context) {showDialog(context: context,builder: (context) => AlertDialog(title: Text('Error'),content: Text('This is an error message.'),actions: [TextButton(onPressed: () => Navigator.pop(context),child: Text('OK'),),],),);}
}
3.创建AlertFactory工厂类

        现在,我们创建一个 AlertFactory 类,根据传入的 AlertType 枚举值返回不同类型的提示框。

enum AlertType { info, warning, error }class AlertFactory {static Alert createAlert(AlertType type) {switch (type) {case AlertType.info:return InfoAlert();case AlertType.warning:return WarningAlert();case AlertType.error:return ErrorAlert();default:throw Exception('Unsupported Alert Type');}}
}

        在 createAlert 方法中,我们使用 switch 语句来判断 AlertType,并返回相应的 Alert 实现类实例。

4.使用AlertFactory展示不同的Alert

        在客户端代码中,我们可以使用 AlertFactory 来创建不同的提示框,而不需要直接实例化具体的 Alert 类。

void main() {runApp(MyApp());
}class MyApp extends StatelessWidget {@overrideWidget build(BuildContext context) {return MaterialApp(home: Scaffold(appBar: AppBar(title: Text('Factory Pattern Demo')),body: Center(child: Column(mainAxisAlignment: MainAxisAlignment.center,children: [ElevatedButton(onPressed: () {Alert alert = AlertFactory.createAlert(AlertType.info);alert.showAlert(context);},child: Text('Show Info Alert'),),ElevatedButton(onPressed: () {Alert alert = AlertFactory.createAlert(AlertType.warning);alert.showAlert(context);},child: Text('Show Warning Alert'),),ElevatedButton(onPressed: () {Alert alert = AlertFactory.createAlert(AlertType.error);alert.showAlert(context);},child: Text('Show Error Alert'),),],),),),);}
}

        在上述实例中,AlertFactory 类的 createAlert 方法根据传入的 AlertType 返回不同的 Alert 实例,showAlert 方法在 Alert 子类中定义了各自的提示框样式,在客户端代码中,可以通过调用 AlertFactory.createAlert 方法来获取相应的提示框实例并展示提示。

4.建造者模式(Builder)

 1.概念

        在Flutter中,建造者模式(Builder Pattern)是一种创建型设计模式,它允许一步一步地创建复杂对象的不同表示方式。通过这种模式,可以更灵活地构建不同配置的对象,尤其是在需要逐步设置对象的属性或处理多个可选属性时非常有用。

        以下是一个使用建造者模式的示例,在这个示例中,我们将实现一个自定义的 UserProfile 类,它具有多个属性(如名字、年龄、头像、简介等)。我们会使用建造者模式来逐步构建这个类的对象。

2.实现步骤

        我们将创建一个 UserProfile 类,并通过建造者模式来灵活地设置不同属性以创建完整的用户简介对象。

1.定义UserProfile类

        首先,定义 UserProfile 类,并将其设置为不可变的类,同时使其属性通过 UserProfileBuilder 类来设置。

class UserProfile {final String name;final int age;final String? avatarUrl;final String? bio;// 构造函数私有化,确保只能通过 Builder 创建UserProfile._({required this.name,required this.age,this.avatarUrl,this.bio,});@overrideString toString() {return 'UserProfile(name: $name, age: $age, avatarUrl: $avatarUrl, bio: $bio)';}
}
2.创建UserProfileBuilder类

       接下来,创建 UserProfileBuilder 类,用于逐步构建 UserProfile 对象。

class UserProfileBuilder {// 定义用户属性,并提供默认值String? _name;int? _age;String? _avatarUrl;String? _bio;// 设置用户名UserProfileBuilder setName(String name) {_name = name;return this;}// 设置用户年龄UserProfileBuilder setAge(int age) {_age = age;return this;}// 设置用户头像URLUserProfileBuilder setAvatarUrl(String avatarUrl) {_avatarUrl = avatarUrl;return this;}// 设置用户简介UserProfileBuilder setBio(String bio) {_bio = bio;return this;}// 构建UserProfile对象UserProfile build() {// 确保必须属性不为空if (_name == null || _age == null) {throw Exception("Name and age must not be null");}return UserProfile._(name: _name!,age: _age!,avatarUrl: _avatarUrl,bio: _bio,);}
}
3.使用UserProfileBuilder创建UserProfile对象

        在客户端代码中,可以使用 UserProfileBuilder 来构建一个用户简介对象,设置不同的属性,然后调用 build() 方法生成最终的 UserProfile 实例。

void main() {// 使用建造者模式创建UserProfileUserProfile user = UserProfileBuilder().setName("Alice").setAge(25).setAvatarUrl("https://example.com/avatar.jpg").setBio("Flutter developer and open-source enthusiast.").build();print(user);// 还可以创建一个更简略的UserProfile对象UserProfile minimalUser = UserProfileBuilder().setName("Bob").setAge(30).build();print(minimalUser);
}

        在上面的实例代码中:    

        serProfile:这是一个不可变的类,属性设置为 final,并且构造函数为私有,以确保只能通过 UserProfileBuilder 创建实例。

         UserProfileBuilder:提供设置属性的链式方法(如 setName、setAge 等),每个方法都返回 this,以支持链式调用。build() 方法用于生成最终的 UserProfile 对象。

        构建用户简介:通过 UserProfileBuilder 的链式方法,可以灵活地设置所需的属性,最终通过 build() 方法生成 UserProfile。

5.原型模式(Prototype)

 1.概念

        在Flutter中,原型模式(Prototype Pattern)是一种创建型设计模式,用于通过克隆已有的对象来创建新对象,而不是直接实例化类。它适用于创建开销较大的对象,或在需要多个相似对象的场景下使用。

2.实现步骤

        下面是一个使用原型模式的示例,在这个示例中,我们将实现一个可克隆的 Shape 类,用于创建不同形状的对象(例如矩形和圆形),并通过克隆现有对象来生成新对象。

        在 Dart 中,我们可以通过 factory 构造函数来实现单例模式。factory 构造函数可以控制实例的创建,并确保只创建一个实例。

        假设我们有一个 Shape 抽象类,并通过原型模式来克隆出不同类型的形状对象。

1.定义Shape抽象类

        首先,我们定义一个 Shape 抽象类,并添加一个 clone 方法,用于返回当前对象的克隆。

abstract class Shape {String color;Shape(this.color);// 定义克隆方法Shape clone();// 描绘形状的方法void draw();
}
2.创建具体的Shape子类

        接下来,创建两个 Shape 的具体实现类:Rectangle 和 Circle,并在 clone 方法中实现对象的克隆逻辑。

class Rectangle extends Shape {double width;double height;Rectangle(String color, this.width, this.height) : super(color);@overrideShape clone() {return Rectangle(color, width, height);}@overridevoid draw() {print("Drawing Rectangle: color=$color, width=$width, height=$height");}
}class Circle extends Shape {double radius;Circle(String color, this.radius) : super(color);@overrideShape clone() {return Circle(color, radius);}@overridevoid draw() {print("Drawing Circle: color=$color, radius=$radius");}
}
3.使使用克隆创建新对象

        在客户端代码中,我们可以通过调用 clone 方法来克隆现有的对象,而无需直接创建新实例。

void main() {// 创建一个矩形原型对象Rectangle rectangle = Rectangle("blue", 10.0, 20.0);rectangle.draw();// 克隆矩形对象Rectangle clonedRectangle = rectangle.clone() as Rectangle;clonedRectangle.color = "red"; // 修改克隆对象的颜色clonedRectangle.draw();// 创建一个圆形原型对象Circle circle = Circle("green", 15.0);circle.draw();// 克隆圆形对象Circle clonedCircle = circle.clone() as Circle;clonedCircle.color = "yellow"; // 修改克隆对象的颜色clonedCircle.draw();
}

        在这个示例中,我们使用了原型模式的克隆特性,通过 clone 方法可以方便地创建相似的对象。原型模式在需要生成相同或相似配置的对象时非常实用。

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

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

美食网的设计与实现

摘 要 随着科技的发展、生活水平的提升&#xff0c;人们更加注重饮食搭配和饮食健康。通过网络技术来加强美食与健康知识的普及是当前一种可行的措施。通过网页浏览美食网&#xff0c;不仅可以普及每道美食的做法&#xff0c;通过制作美食来缓解心情&#xff0c;还可以通过美…

2024-2025年EI会议时间表,把握未来学术研讨机遇

2024-2025年多场国际学术会议将在中国多地举办&#xff0c;涵盖网络、通信、AI等领域&#xff0c;均支持EI等检索。会议时间、地点及检索信息已提供&#xff0c;涉及北京、淮北、深圳等城市。 以下是部分精品学术会议基本信息&#xff0c;欢迎点击链接查看&#xff1a; 第二届…

QML —— 圆形波浪进度条控件(附上源码)

效果 说明 QML中使用画布元素(canvas element),使用画布元素可画出各种各样的图形,同时允许脚本绘制。画布元素提供了一个依赖于分辨率的位图画布,也可以使用JavaScript脚本来绘制图形,制作游戏或者其它的动态图像。QML中的画布元素是基于HTML5的画布元素来完成的。    …

echarts引入自定义字体不起作用问题记录

echarts引入自定义字体不起作用问题记录 1、问题描述 初始化界面字体不作用&#xff0c;当界面更新后字体样式正常显示 2、原因描述 这通常是由于字体文件加载延迟导致的。ECharts 在初始化时可能还没有加载完字体文件&#xff0c;因此无法正确应用字体样式 3、解决方案 …

UE5.4 PCG 生成藤蔓墙体

一、新建Actor&#xff0c;添加Spline组件&#xff0c;挂上PCG组件&#xff0c;设置“墙体”和“植被”为静态网格体变量 二、编写PCG_Wall 1.生成墙体 2.生成墙体植被

【网络】子网掩码

> 作者&#xff1a;დ旧言~ > 座右铭&#xff1a;松树千年终是朽&#xff0c;槿花一日自为荣。 > 目标&#xff1a;了解什么是子网掩码&#xff0c;并且能熟练掌握子网掩码的相关计算。 > 毒鸡汤&#xff1a;有些事情&#xff0c;总是不明白&#xff0c;所以我不会…

Worldly平台更新Higg FEM 2024模块价格及购买指南

近日&#xff0c;LEVERAGE供应链管理从美国可持续服装联盟&#xff08;Cascale&#xff09;验证官方Worldly平台模块订阅更新中获悉&#xff0c;FEM2024模块价格更新的重要信息。此次更新涉及工厂环境模块&#xff08;FEM&#xff09;和工厂社会劳工模块&#xff08;FSLM&#…

Rocky9通过Docker-compose部署zabbix 7.0.5

Rocky9通过Docker-compose部署zabbix 7.0.5 1. 实验环境架构2. Zabbix-Server准备工作2.1 更新仓库2.2 安装docker-ce2.3 安装docker-compose 3. 安装Zabbix项目3.1 克隆项目3.2 预下载镜像3.3 启动Zabbix 4. 启动web管理端4.1 登录web管理页4.2 修改时区和语言 5. Agent安装配…

企业内训系统

在当今这个竞争激烈的市场环境中&#xff0c;企业的持续发展不仅依赖于外部市场的拓展&#xff0c;更离不开内部团队能力的提升。企业内训系统&#xff0c;作为提升企业竞争力、促进员工成长的重要工具&#xff0c;正逐渐成为现代企业管理中不可或缺的一环。本文将深入探讨企业…

QT自定义控件封装

QT自定义控件封装 1.概述 这篇文章介绍如何创建UI文件&#xff0c;通过自定义方式将两个控件联动起来&#xff0c;实现自定义功能。 2.创建UI文件 新建一个widget的普通项目&#xff0c;然后在项目名称上右键选择And New... 新建文件&#xff0c;然后选择QT 再选择Qt Desig…

物联网(RFID)全景:被装信息化监控应用与挑战

一、被装物联网信息化建设的动因 信息化改革在20世纪80年代中期启航&#xff0c;旨在提升被装保障的效率。随着时间的推移&#xff0c;硬件的广泛运用和软件的快速迭代&#xff0c;装备业务在规划、制造、分发以及战时支援等核心环节&#xff0c;已经与信息系统深度融合&#x…

屏幕解析工具——OmniParser

0 引言 OmniParser是微软开源的一种屏幕解析工具&#xff0c;提供了一种将用户界面截图解析为结构化元素的综合方法&#xff0c;通过此方法可以对UI界面进行可交互元素的提取和描述&#xff0c;然后将此结构化信息和任务指令&#xff0c;输入到大模型中&#xff0c;以增强大模…

衡石分析平台系统分析人员手册-嵌入样式定制化指南­

发布页面嵌入样式定制化指南​ 使用衡石智能分析平台制作好 Dashboard 和 Chart 以后&#xff0c;可以通过 iframe 的方式嵌入到已有系统中。为了达到风格统一&#xff0c;嵌入 iframe 的时候支持丰富的定制化选项。 定制 Dashboard 的 iframe​ 参数列表​ 仪表盘嵌入时支持…

Nginx更换ssl证书不生效

一.场景 在用的ssl证书要过期了&#xff0c;申请了新的ssl证书下来&#xff0c;在nginx配置上更换上去后&#xff0c;打开系统地址&#xff0c;一依然是使用原来的旧证书&#xff0c;以前有更换过别的域名证书&#xff0c;重启nginx服务后立马就生效了。 这次没生效&#xff…

基于python和Django的用户管理接口开发

1.异步用户登录\登出接口开发 1.设计公共响应数据类型 文件地址&#xff1a;utils/response404.py from django.http import JsonResponseclass BadRequestJsonResponse(JsonResponse):status_code 400def __init__(self, err_list, *args, **kwargs):data {"error_c…

Docker--Docker是什么和对Docker的了解

Docker 的本质 Docker的本质是LXC&#xff08;Linux容器&#xff09;之类的增强版&#xff0c;它本身不是容器&#xff0c;而是容器的易用工具。 Docker通过虚拟化技术&#xff0c;将代码、依赖项和运行环境打包成一个容器&#xff0c;并利用隔离机制来使得容器之间互相独立、…

Window下PHP安装最新sg11(php5.3-php8.3)

链接: https://pan.baidu.com/s/10yyqTJdwH_oQJnQtWcwIeA 提取码: qz8y 复制这段内容后打开百度网盘手机App&#xff0c;操作更方便哦 (链接失效联系L88467872) 1.下载后解压文件&#xff0c;将对应版本的ixed.xx.win文件放进php对应的ext目录下&#xff0c;如图所示 2.修改ph…

C# yolo10使用onnx推理

一、前言 本篇总结C#端使用yolo10的onnx文件做模型推理&#xff0c;主要使用Microsoft.ML.OnnxRuntime.Gpu这个库。需要注意的是Microsoft.ML.OnnxRuntime 和 Microsoft.ML.OnnxRuntime.Gpu 这2库只装1个就行&#xff0c;CPU就装前者&#xff0c;反之后者。然后需要注意系统安装…

MNIST数据集下载与保存为图片格式

深度学习 文章目录 深度学习下载数据集 下载数据集 https://github.com/geektutu/tensorflow-tutorial-samples/tree/master/mnist/data_set t10k-images-idx3-ubyte.gz t10k-labels-idx1-ubyte.gz train-images-idx3-ubyte.gz train-labels-idx1-ubyte.gz 解压后&#xff0c;…

Oracle In子句

Oracle IN 运算符可以用来确定值是否与列表或子查询中的任何值相匹配 Oracle IN语法&#xff1a; 确定表达式是否与值列表匹配的 Oracle IN 运算符的语法如下所示&#xff1a; expression [NOT] IN (v1,v2,...)并且表达式的语法与子查询匹配&#xff1a; expression [NOT] I…