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.)
}

未完待续

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

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

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

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

相关文章

web实操1——只使用tomcat发布网站

安装tomcat 下载 肯定是去官网: http://tomcat.apache.org/ 下载之后,解压: !!解压后: logs日志:就是一些输出,输到文本里。 temp:一些临时文件(不用管) webapps:放网站的 work&…

数据结构:七种排序及总结

文章目录 排序一插入排序1直接插入排序2希尔排序二选择排序3直接选择排序4堆排序三 交换排序5冒泡排序6快速排序四 归并排序7归并排序源码 排序 我们数据结构常见的排序有四大种,四大种又分为七小种,如图所示 排序:所谓排序,就是…

A day a tweet(sixteen)——The better way of search of ChatGPT

Introducing ChatGPT search a/ad.及时的/及时地 ChatGPT can now search the web in a much better way than before so you get fast, timely a.有关的(relative n.亲戚,亲属;同类事物 a.比较的;相对的) answers with link…

HTMLCSS:呈现的3D树之美

效果演示 这段代码通过HTML和CSS创建了一个具有3D效果的树的图形&#xff0c;包括分支、树干和阴影&#xff0c;通过自定义属性和复杂的变换实现了较为逼真的立体效果。 HTML <div class"container"><div class"tree"><div class"…

系统规划与管理师——第十二章 职业素养与法侓法规

目录 职业素养 职业道德 行为规范 职业责任 对客户和公众的责任 法律法规 法律概念 法律体系 诉讼时效 民事诉讼时效 刑事追诉时效 常用的法律法规 合同法 招投标法 著作权法 政府采购法 劳动法 知识产权法 刑法修正案&#xff08;七) IT服务的广泛应用不仅…

HAL库硬件IIC驱动气压传感器BMP180

环境 1、keilMDK 5.38 2、STM32CUBEMX 初始配置 默认即可。 程序 1、头文件 #ifndef __BMP_180_H #define __BMP_180_H#include "main.h"typedef struct {float fTemp; /*温度&#xff0c;摄氏度*/float fPressure; /*压力&#xff0c;pa*/float fAltitude; /*…

沈阳乐晟睿浩科技有限公司抖音小店展望未来

在当今数字化浪潮汹涌的时代&#xff0c;电子商务以其独特的魅力和无限潜力&#xff0c;正深刻改变着人们的消费习惯与商业模式。抖音小店作为短视频与电商深度融合的产物&#xff0c;凭借其庞大的用户基础、精准的内容推送机制以及独特的购物体验&#xff0c;迅速崛起为电商领…

【论文复现】自动化细胞核分割与特征分析

本文所涉及所有资源均在这里可获取。 作者主页&#xff1a; 七七的个人主页 文章收录专栏&#xff1a; 论文复现 欢迎大家点赞 &#x1f44d; 收藏 ⭐ 加关注哦&#xff01;&#x1f496;&#x1f496; 自动化细胞核分割与特征分析 引言效果展示HoverNet概述HoverNet原理分析整…

ESP32 gptimer通用定时器初始化报错:assert failed: timer_ll_set_clock_prescale

背景&#xff1a;IDF版本V5.1.2 &#xff0c;配置ESP32 通用定时器&#xff0c;实现100HZ&#xff0c;占空比50% 的PWM波形。 根据乐鑫官方的IDF指导文档设置内部计数器的分辨率&#xff0c;计数器每滴答一次相当于 1 / resolution_hz 秒。 &#xff08;ESP-IDF编程指导文档&a…

Jest项目实战(4):将工具库顺利迁移到GitHub的完整指南

开源代码&#xff1a;将工具库迁移到GitHub 随着项目的成熟和完善&#xff0c;将其开源不仅可以获得更多的用户和贡献者&#xff0c;还能促进项目本身的发展。GitHub作为全球最大的开源协作平台&#xff0c;自然成为了大多数开发者的首选。本文将引导您完成将工具库迁移至GitH…

C#线程池

目录 前言 线程 线程池 线程池的工作原理 重要方法 C#线程池总结 前言 线程池是一种多线程处理形式&#xff0c;它允许开发者将任务添加到队列中&#xff0c;然后线程池会自动管理线程的创建、分配和回收&#xff0c;以执行这些任务。线程池中的线程都是后台线程&#xf…

SpringBoot项目集成ONLYOFFICE

ONLYOFFICE 文档8.2版本已发布&#xff1a;PDF 协作编辑、改进界面、性能优化、表格中的 RTL 支持等更新 文章目录 前言ONLYOFFICE 产品简介功能与特点Spring Boot 项目中集成 OnlyOffice1. 环境准备2. 部署OnlyOffice Document Server3. 配置Spring Boot项目4. 实现文档编辑功…

用示例来看C2Rust工具的使用和功能介绍

C2Rust可以将C语言的源代码转换成Rust语言的源代码。下面是一个简单的C语言代码示例&#xff0c;以及使用c2Rust工具将其转换为Rust安全代码的过程。 C语言源代码示例 // example.c #include <stdio.h>int add(int a, int b) {return a b; }int main() {int result a…

【IC验证】systemverilog的设计特性

systemverilog的设计特性 一.概述二.面向硬件的过程语句块1.说明2.always_comb2.always_latch3.always_ff 三.关系运算符1.说明2.例子 四.inside判定符1.说明2.例子 五.条件分支语句&#xff08;1&#xff09;说明&#xff08;2&#xff09;例子&#xff08;case和unique case的…

计算不停歇,百度沧海数据湖存储加速方案 2.0 设计和实践

数据湖这个概念&#xff0c;从 2012 年产生到现在已经有十余年的时间&#xff0c;每家公司对它内涵的解读都不太一样。但是数据湖的主要存储底座有从传统的 HDFS 向对象存储演进的趋势。 传统的大数据计算场景&#xff0c;比如 MapReduce、Spark、Hive 这些大数据组件都是基于…

信息化运维方案,实施方案,开发方案,信息中心安全运维资料(软件资料word)

1 编制目的 2 系统运行维护 2.1 系统运维内容 2.2 日常运行维护方案 2.2.1 日常巡检 2.2.2 状态监控 2.2.3 系统优化 2.2.4 软件系统问题处理及升级 2.2.5 系统数据库管理维护 2.2.6 灾难恢复 2.3 应急运行维护方案 2.3.1 启动应急流程 2.3.2 成立应急小组 2.3.3 应急处理过程 …

【网络面试篇】HTTP(2)(笔记)——http、https、http1.1、http2.0

目录 一、相关面试题 1. HTTP 与 HTTPS 有哪些区别&#xff1f; 2. HTTPS 的工作原理&#xff1f;&#xff08;https 是怎么建立连接的&#xff09; &#xff08;1&#xff09;ClientHello &#xff08;2&#xff09;SeverHello &#xff08;3&#xff09;客户端回应 &a…

使用文心快码生成口算题,妈妈再也不用担心我的学习了

2024年10月NJSD技术盛典暨第十届NJSD软件开发者大会、第八届IAS互联网架构大会在南京召开。百度文心快码总经理臧志分享了《AI原生研发新范式的实践与思考》&#xff0c;探讨了大模型赋能下的研发变革及如何在公司和行业中落地&#xff0c;AI原生研发新范式的内涵和推动经验。 …

C#笔记 —— 事件

事件的语法 访问修饰符 event 委托类型 事件名&#xff1b; 例&#xff1a; public event Action myEvent; 事件的使用 事件的使用跟委托基本上一模一样&#xff0c; 1.但是事件不能在类外部直接赋值&#xff0c;只能使用 或 - 添加或删除函数&#xff1b; 2.事件不能在类…

JavaScript3*3表格实现每次点击只红一行

<script> window.onload function () { var myTd document.getElementsByTagName("td"); var currentlyHighlightedRow null; // 用于存储当前高亮显示的行 for (var i 0; i < myTd.length; i) { myTd[i].onclick function () { …