当前位置: 首页 > news >正文

Flutter 中的那些设计模式的写法(持续更新)

前言

我们都知道设计模式是相同的,同一种设计模式的理念不会因为语言不同而会有所改变,但是由于语法的差异,设计模式的写法也有所差异,本文会介绍一些flutter中常用设计模式的写法以及使用场景。
常见的设计模式有23种,按照类型可以细分为:
创建型模式

  • 单例模式 (Singleton)
  • 工厂方法模式 (Factory Method)
  • 抽象工厂模式 (Abstract Factory)
  • 建造者模式 (Builder)
  • 原型模式 (Prototype)

结构型模式

  • 适配器模式 (Adapter)
  • 桥接模式 (Bridge)
  • 组合模式 (Composite)
  • 装饰模式 (Decorator)
  • 外观模式 (Facade)
  • 享元模式 (Flyweight)
  • 代理模式 (Proxy)

行为型模式

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

单例模式

想必对于大部分的开发来说,这是咱们接触最多的设计模式之一了。
单例模式(Singleton Pattern)理念

唯一实例: 单例模式保证了某个类只有一个实例存在。这意味着无论何时何地调用该类,只会返回同一个对象实例。
全局访问: 提供一个全局访问点来获取该唯一实例。通常通过一个静态方法或属性来实现。
延迟实例化: 单例模式通常支持延迟实例化,即在第一次请求时创建实例,以节省资源。

设计思路:

私有构造函数: 将类的构造函数设为私有,以防止外部通过普通构造方法创建实例。
静态实例: 使用静态变量存储类的唯一实例。
静态方法: 提供一个公共的静态方法或属性,返回该唯一实例。

代码实现

1. 饿汉式单例

这种方式在类加载时就创建实例,线程安全,但如果实例初始化开销大且不一定会用到,会造成资源浪费。

class Singleton {//私有构造函数Singleton._privateConstructor();// 静态实例static final Singleton instance = Singleton._privateConstructor();// 内部方法void printHello() {print('Hello');}
}
//调用方式Singleton.instance.printHello();

2. 懒汉式单例
这种方式在第一次使用时才创建实例,延迟加载。

class SingletonLazy {//私有构造SingletonLazy._privateConstructor();//静态实例static SingletonLazy? _instance;//获取实列方法static SingletonLazy getInstance() {if (_instance == null) {_instance = SingletonLazy._privateConstructor();}return _instance!;}
}

也可以通过dart中的工厂类来创建懒汉式

class SingletonFactory {// 私有构造函数SingletonFactory._privateConstructor();// 静态变量来存储唯一实例static SingletonFactory? _instance;// 工厂构造函数factory SingletonFactory() {if (_instance == null) {_instance = SingletonFactory._privateConstructor();}return _instance!;}void someMethod() {print('This is a method in SingletonFactory');}
}

3.静态内部类
这种方式利用 Dart 的静态内部类特性,既实现了延迟加载,又保证了线程安全。

class Singleton {// 私有构造函数Singleton._privateConstructor();// 静态内部类static final Singleton instance = _SingletonHolder.instance;// 内部类static class _SingletonHolder {static final Singleton instance = Singleton._privateConstructor();}
}

4. 懒汉式双重检查

额~~~写java过来的人条件反射就是,单例要考虑线程安全,加锁。。。
其实在flutter中,由于Flutter是单线程模式的,很少会有多线程切换的使用场景,它的异步操作是通过Future来实现的,其内部也是通过堆栈来实现阻塞(await)和插件队列执行,理论上是线程安全的,除非你非得使用Isolates,但是Isolates一种多线程模型,每个 Isolate 拥有独立的内存空间,因此单例在不同的 Isolate 中不会共享。这意味着在 Dart 中,通常不需要担心传统意义上的多线程竞争条件。所以个人觉得,没有必要加锁考虑并发情况,非得写考虑 静态内部类

工厂设计模式

在 Flutter 中,工厂设计模式(Factory Pattern)是一种创建型设计模式,用于定义一个接口或抽象类以创建对象,但让子类决定要实例化的类。工厂模式可以将实例化对象的逻辑与使用对象的逻辑分离,提高代码的可扩展性和可维护性。
像支付(不同的支付类型)、日志、等都可以使用该模式

工厂模式的主要分类

  1. 简单工厂模式: 提供一个创建对象实例的方法,根据传入的参数决定创建哪种类型的对象。
  2. 抽象工厂模式:提供一个接口,用于创建相关或依赖对象的家族,而无需明确指定具体类。

简单工厂模式
简单工厂模式通过一个静态方法创建对象实例。

//对象实例子
abstract class Shape {void draw();
}
//实现抽象方法,重写自己的实例子
class Circle implements Shape {void draw() {print("Drawing a Circle");}
}class Square implements Shape {void draw() {print("Drawing a Square");}
}class ShapeFactory {
// 创建静态方法,通过传入不同的类型来判断要执行的工厂类static Shape createShape(String type) {if (type == 'circle') {return Circle();} else if (type == 'square') {return Square();} else {throw Exception("Shape type $type not recognized");}}
}
// 调用实现
void main() {Shape circle = ShapeFactory.createShape('circle');circle.draw(); // 输出: Drawing a CircleShape square = ShapeFactory.createShape('square');square.draw(); // 输出: Drawing a Square
}

抽象工厂模式
抽象工厂模式用于创建相关或依赖对象的家族。

abstract class Button {void paint();
}class WindowsButton implements Button {void paint() {print("Rendering a button in Windows style");}
}class MacOSButton implements Button {void paint() {print("Rendering a button in MacOS style");}
}abstract class GUIFactory {Button createButton();
}class WindowsFactory implements GUIFactory {Button createButton() {return WindowsButton();}
}class MacOSFactory implements GUIFactory {Button createButton() {return MacOSButton();}
}void main() {GUIFactory factory = WindowsFactory();Button button = factory.createButton();button.paint(); // 输出: Rendering a button in Windows stylefactory = MacOSFactory();button = factory.createButton();button.paint(); // 输出: Rendering a button in MacOS style
}

策略设计模式

在 Flutter 中,策略模式(Strategy Pattern)是一种常用的设计模式,它允许你定义一系列算法,将每一个算法封装起来,并且使它们可以互相替换。而不用每次改动都去修改代码实现,策略模式可以让我们不用关注算法的具体实现是什么。

策略模式的结构

  • 策略接口(Strategy Interface): 定义算法或行为的接口。
  • 具体策略(Concrete Strategies): 实现策略接口的不同算法。
  • 上下文(Context): 维护对策略对象的引用,并在需要时调用策略对象的方法。

我们以用算不同类型的折扣为例。策略模式可以帮助我们在不同的折扣计算方法之间切换。

  1. 定义策略接口
    首先,定义一个策略接口,描述不同折扣算法的通用方法。
abstract class DiscountStrategy {
//计算折扣金额double calculateDiscount(double price);
}

2. 实现具体策略
为不同的折扣类型算法的具体的策略类。

//无折扣
class NoDiscountStrategy implements DiscountStrategy {double calculateDiscount(double price) {return 0.0;}
}
//具体折扣
class PercentageDiscountStrategy implements DiscountStrategy {final double percentage;PercentageDiscountStrategy(this.percentage);double calculateDiscount(double price) {return price * (percentage / 100);}
}
//全免
class FixedAmountDiscountStrategy implements DiscountStrategy {final double discountAmount;FixedAmountDiscountStrategy(this.discountAmount);double calculateDiscount(double price) {return discountAmount;}
}

3. 创建上下文
定义一个上下文类(Context),用于持有策略对象,并在需要时调用策略的方法。

class ShoppingCart {DiscountStrategy _discountStrategy;ShoppingCart(this._discountStrategy);void setDiscountStrategy(DiscountStrategy strategy) {_discountStrategy = strategy;}//计算打完折后的最终价格double calculateFinalPrice(double price) {double discount = _discountStrategy.calculateDiscount(price);return price - discount;}
}

4. 使用策略模式
现在可以在应用程序中使用策略模式,根据不同的需求动态选择折扣策略。

void main() {double itemPrice = 100.0;ShoppingCart cart = ShoppingCart(NoDiscountStrategy());print("Final price with no discount: ${cart.calculateFinalPrice(itemPrice)}");cart.setDiscountStrategy(PercentageDiscountStrategy(10));print("Final price with 10% discount: ${cart.calculateFinalPrice(itemPrice)}");cart.setDiscountStrategy(FixedAmountDiscountStrategy(15));print("Final price with $15 discount: ${cart.calculateFinalPrice(itemPrice)}");
}

建造者模式(Builder Pattern)

建造者模式(Builder Pattern)是一种创建型设计模式,它允许使用者一步步构建一个复杂对象。与直接使用构造函数或工厂模式不同,建造者模式提供了一种灵活的方式来创建对象,特别是当对象的创建过程涉及多个步骤或需要复杂配置时。

在 Flutter 中,建造者模式(链式调用)可以用于构建复杂的 UI 组件或对象配置,像UI组件的封装使用构建者模式是非常常用的。

建造者模式的结构

  • 产品(Product): 需要构建的复杂对象。
  • 建造者接口(Builder Interface): 定义创建产品对象的所有步骤。
  • 具体建造者(Concrete Builder): 实现 Builder 接口,并提供创建产品的具体步骤。
  • 指挥者(Director): 控制构建过程,按顺序调用建造者中的各个步骤。

下面以封装一个UI组件为例:
1. 定义产品
首先,定义需要创建的复杂对象(对象参数比较多,或者链路很长)。

class ComplexWidget {String? title;String? imageUrl;String? description;String toString() {return 'ComplexWidget(title: $title, imageUrl: $imageUrl, description: $description)';}
}

2. 定义建造者接口
定义一个接口,描述创建产品的步骤。

abstract class ComplexWidgetBuilder {void setTitle(String title);void setImageUrl(String imageUrl);void setDescription(String description);ComplexWidget getResult();
}

3. 实现具体建造者
实现建造者接口,提供具体的构建步骤。

class ConcreteComplexWidgetBuilder implements ComplexWidgetBuilder {final ComplexWidget _complexWidget = ComplexWidget();void setTitle(String title) {_complexWidget.title = title;}void setImageUrl(String imageUrl) {_complexWidget.imageUrl = imageUrl;}void setDescription(String description) {_complexWidget.description = description;}ComplexWidget getResult() {return _complexWidget;}
}

4. 定义指挥者
定义一个指挥者类,用于控制构建过程。

class Director {late ComplexWidgetBuilder _builder;void setBuilder(ComplexWidgetBuilder builder) {_builder = builder;}ComplexWidget buildCompleteWidget() {_builder.setTitle("Sample Title");_builder.setImageUrl("http://example.com/image.png");_builder.setDescription("This is a sample description.");return _builder.getResult();}
}

5. 使用建造者模式
在应用程序中使用建造者模式来创建复杂对象。

void main() {Director director = Director();ComplexWidgetBuilder builder = ConcreteComplexWidgetBuilder();director.setBuilder(builder);ComplexWidget widget = director.buildCompleteWidget();print(widget);// 输出: ComplexWidget(title: Sample Title, imageUrl: http://example.com/image.png, description: This is a sample description.)
}

未完待续

后面慢慢会把常用的设计模式都在这里做更新。。。

每个设计模式都有自己的优缺点,其实适合自己的才是最合理的,不要为了设计代码而设计代码,如果不理解业务场景强上设计模式,只会让代码写的更复杂

相关文章:

Flutter 中的那些设计模式的写法(持续更新)

前言 我们都知道设计模式是相同的,同一种设计模式的理念不会因为语言不同而会有所改变,但是由于语法的差异,设计模式的写法也有所差异,本文会介绍一些flutter中常用设计模式的写法以及使用场景。 常见的设计模式有23种&#xff0…...

【提效工具开发】Python功能模块执行和 SQL 执行 需求整理

需求梳理 背景 当前我们在IDE或MySQL查询工具中只能进行个人使用,缺乏共享功能,且在查询及数据统计上有一定的不便。为了改善这种情况,计划搭建一个Web平台,通过后台交互来提升效率。此平台需要兼容Python工具和SQL工具的管理、执…...

Linux系列-进程的状态

🌈个人主页:羽晨同学 💫个人格言:“成为自己未来的主人~” 操作系统就是计算机领域的哲学,是为了保证在所有情况下都适用,加载到内存叫做新建状态。 并行和并发 计算机同时进行多个任务,在用户感知的…...

SpringBoot项目中常用的一些注解

一、核心注解 SpringBootApplication 作用:标注一个主程序类,表明这是一个Spring Boot应用程序的入口。说明:这是一个复合注解,组合了Configuration、EnableAutoConfiguration和ComponentScan。 EnableAutoConfiguration 作用&…...

【网络】自定义协议——序列化和反序列化

> 作者:დ旧言~ > 座右铭:松树千年终是朽,槿花一日自为荣。 > 目标:了解什么是序列化和分序列,并且自己能手撕网络版的计算器。 > 毒鸡汤:有些事情,总是不明白,所以我不…...

Pytorch如何精准记录函数运行时间

0. 引言 参考Pytorch官方文档对CUDA的描述,GPU的运算是异步执行的。一般来说,异步计算的效果对于调用者来说是不可见的,因为 每个设备按照排队的顺序执行操作Pytorch对于CPU和GPU的同步,GPU间的同步是自动执行的,不需…...

使用 Java 实现邮件发送功能

引言 1. JavaMail API 简介 2. 环境准备 2.1 Maven 依赖 2.2 Gradle 依赖 3. 发送简单文本邮件 4. 发送 HTML 邮件 5. 发送带附件的邮件 6. 注意事项 引言 在现代应用开发中,邮件发送功能是非常常见的需求,例如用户注册验证、密码重置、订单确认…...

html第一个网页

创建你的第一个HTML网页是一个激动人心的步骤。以下是创建一个简单网页的基本步骤和代码示例&#xff1a; 基础结构&#xff1a;所有的HTML文档都应该包含以下基本结构。 <!DOCTYPE html> <html> <head><title>我的第一个网页</title> </he…...

前后端交互接口(三)

前后端交互接口&#xff08;三&#xff09; 前言 前两集我们先做了前后端交互接口的约定以及浅浅的阅读了一些proto代码。那么这一集我们就来看看一些重要的proto代码&#xff0c;之后把protobuffer给引入我们的项目当中&#xff01; gateway.proto 我们来看一眼我们的网关…...

华为Mate70前瞻,鸿蒙NEXT正式版蓄势待发,国产系统迎来关键一战

Mate 70系列要来了 上个月&#xff0c;vivo、小米、OPPO、荣耀等众多智能手机制造商纷纷发布了他们的年度旗舰产品&#xff0c;手机行业内竞争异常激烈。 同时&#xff0c;华为首席执行官余承东在其个人微博上透露&#xff0c;Mate 70系列将标志着华为Mate系列手机达到前所未有…...

【安卓13 源码】Input子系统(4)- InputReader 数据处理

1. 多指触控协议 多指触控协议有 2 种&#xff1a; > A类&#xff1a; 处理无关联的接触&#xff1a; 用于直接发送原始数据&#xff1b; > B类&#xff1a; 处理跟踪识别类的接触&#xff1a; 通过事件slot发送相关联的独立接触更新。 B协议可以使用一个ID来标识触点&…...

Xserver v1.4.2发布,支持自动重载 nginx 配置

Xserver——优雅、强大的 php 集成开发环境 本次更新为大家带来了更好的用户体验。 &#x1f389; 下载依赖组件时&#xff0c;显示进度条&#xff0c;展示下载进度。 &#x1f389; 保存站点信息和手动修改 vhost 配置文件之后&#xff0c;自动重载 nginx 配置 &#x1f41e…...

Java反射原理及其性能优化

目录 JVM是如何实现反射的反射的性能开销体现在哪里如何优化反射性能开销 1. JVM是如何实现反射的? 反射是Java语言中的一种强大功能&#xff0c;它允许程序在运行时动态地获取类的信息以及操作对象。下面是一个简单的示例&#xff0c;演示了如何使用反射调用方法&#xff…...

RabbitMQ 管理平台(控制中心)的介绍

文章目录 一、RabbitMQ 管理平台整体介绍二、Overview 总览三、Connections 连接四、Channels 通道五、Exchanges 交换机六、Queues 队列查看队列详细信息查看队列的消息内容 七、Admin 用户给用户分配虚拟主机 一、RabbitMQ 管理平台整体介绍 RabbitMQ 管理平台内有六个模块&…...

【SQL】在 SQL Server 中创建数据源是 MySQL 数据表的视图

背景&#xff1a;Windows系统已安装了mysql5.7和sqlServer数据库&#xff0c;现在需要在sqlServer创建视图或者查询来自mysql的数据&#xff0c;视图的数据来源mysql数据库。下面进行实现在sqlserver实现获取mysql数据表数据构建视图。 1、打开 ODBC 数据源管理器&#xff0c;…...

现代Web开发:Next.js 深度解析与最佳实践

&#x1f493; 博客主页&#xff1a;瑕疵的CSDN主页 &#x1f4dd; Gitee主页&#xff1a;瑕疵的gitee主页 ⏩ 文章专栏&#xff1a;《热点资讯》 现代Web开发&#xff1a;Next.js 深度解析与最佳实践 现代Web开发&#xff1a;Next.js 深度解析与最佳实践 现代Web开发&#xf…...

LeetCode题练习与总结:赎金信--383

一、题目描述 给你两个字符串&#xff1a;ransomNote 和 magazine &#xff0c;判断 ransomNote 能不能由 magazine 里面的字符构成。 如果可以&#xff0c;返回 true &#xff1b;否则返回 false 。 magazine 中的每个字符只能在 ransomNote 中使用一次。 示例 1&#xff1…...

eval: jdk1.8.0_431/jre/bin/java: Permission denied

当您在启动Tomcat或其他Java应用时遇到“Permission denied”错误&#xff0c;这通常表示当前用户没有执行指定Java可执行文件的权限。以下是解决这个问题的几种方法&#xff1a; 方法一&#xff1a;检查文件权限 查看文件权限&#xff1a; 使用ls -l命令查看Java可执行文件的…...

.Net IOC理解及代码实现

IOC理解 IoC(Inversion of Control)&#xff1a;即控制反转&#xff0c;这是一种设计思想&#xff0c;指将对象的控制权交给IOC容器&#xff0c;由容器来实现对象的创建、管理&#xff0c;程序员只需要从容器获取想要的对象就可以了。DI(Dependency Injection)&#xff0c;即依…...

履带机器人(一、STM32控制部分--标准库)

一、履带机器人整体逻辑框架 通过在PC端搭建上位机,使得在PC端可以给STM32发送控制指令并且接受STM32的状态信息。 通过RS485通信,使得STM32可以和电机进行通信,STM32发送启动、停止、转速、方向等指令,并接受电机返回的状态信息。 二、STM32逻辑框架 整体逻辑: 1、先…...

网络编程(Modbus进阶)

思维导图 Modbus RTU&#xff08;先学一点理论&#xff09; 概念 Modbus RTU 是工业自动化领域 最广泛应用的串行通信协议&#xff0c;由 Modicon 公司&#xff08;现施耐德电气&#xff09;于 1979 年推出。它以 高效率、强健性、易实现的特点成为工业控制系统的通信标准。 包…...

eNSP-Cloud(实现本地电脑与eNSP内设备之间通信)

说明&#xff1a; 想象一下&#xff0c;你正在用eNSP搭建一个虚拟的网络世界&#xff0c;里面有虚拟的路由器、交换机、电脑&#xff08;PC&#xff09;等等。这些设备都在你的电脑里面“运行”&#xff0c;它们之间可以互相通信&#xff0c;就像一个封闭的小王国。 但是&#…...

IGP(Interior Gateway Protocol,内部网关协议)

IGP&#xff08;Interior Gateway Protocol&#xff0c;内部网关协议&#xff09; 是一种用于在一个自治系统&#xff08;AS&#xff09;内部传递路由信息的路由协议&#xff0c;主要用于在一个组织或机构的内部网络中决定数据包的最佳路径。与用于自治系统之间通信的 EGP&…...

【磁盘】每天掌握一个Linux命令 - iostat

目录 【磁盘】每天掌握一个Linux命令 - iostat工具概述安装方式核心功能基础用法进阶操作实战案例面试题场景生产场景 注意事项 【磁盘】每天掌握一个Linux命令 - iostat 工具概述 iostat&#xff08;I/O Statistics&#xff09;是Linux系统下用于监视系统输入输出设备和CPU使…...

电脑插入多块移动硬盘后经常出现卡顿和蓝屏

当电脑在插入多块移动硬盘后频繁出现卡顿和蓝屏问题时&#xff0c;可能涉及硬件资源冲突、驱动兼容性、供电不足或系统设置等多方面原因。以下是逐步排查和解决方案&#xff1a; 1. 检查电源供电问题 问题原因&#xff1a;多块移动硬盘同时运行可能导致USB接口供电不足&#x…...

智能仓储的未来:自动化、AI与数据分析如何重塑物流中心

当仓库学会“思考”&#xff0c;物流的终极形态正在诞生 想象这样的场景&#xff1a; 凌晨3点&#xff0c;某物流中心灯火通明却空无一人。AGV机器人集群根据实时订单动态规划路径&#xff1b;AI视觉系统在0.1秒内扫描包裹信息&#xff1b;数字孪生平台正模拟次日峰值流量压力…...

精益数据分析(97/126):邮件营销与用户参与度的关键指标优化指南

精益数据分析&#xff08;97/126&#xff09;&#xff1a;邮件营销与用户参与度的关键指标优化指南 在数字化营销时代&#xff0c;邮件列表效度、用户参与度和网站性能等指标往往决定着创业公司的增长成败。今天&#xff0c;我们将深入解析邮件打开率、网站可用性、页面参与时…...

学校时钟系统,标准考场时钟系统,AI亮相2025高考,赛思时钟系统为教育公平筑起“精准防线”

2025年#高考 将在近日拉开帷幕&#xff0c;#AI 监考一度冲上热搜。当AI深度融入高考&#xff0c;#时间同步 不再是辅助功能&#xff0c;而是决定AI监考系统成败的“生命线”。 AI亮相2025高考&#xff0c;40种异常行为0.5秒精准识别 2025年高考即将拉开帷幕&#xff0c;江西、…...

浪潮交换机配置track检测实现高速公路收费网络主备切换NQA

浪潮交换机track配置 项目背景高速网络拓扑网络情况分析通信线路收费网络路由 收费汇聚交换机相应配置收费汇聚track配置 项目背景 在实施省内一条高速公路时遇到的需求&#xff0c;本次涉及的主要是收费汇聚交换机的配置&#xff0c;浪潮网络设备在高速项目很少&#xff0c;通…...

QT3D学习笔记——圆台、圆锥

类名作用Qt3DWindow3D渲染窗口容器QEntity场景中的实体&#xff08;对象或容器&#xff09;QCamera控制观察视角QPointLight点光源QConeMesh圆锥几何网格QTransform控制实体的位置/旋转/缩放QPhongMaterialPhong光照材质&#xff08;定义颜色、反光等&#xff09;QFirstPersonC…...