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

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 Circle

  Shape 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 style

  factory = 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.kler.cn/a/384648.html

相关文章:

  • 华为交换机Vlan划分
  • 计算不停歇,百度沧海数据湖存储加速方案 2.0 设计和实践
  • 推荐一款基于Flash的交互式园林设计工具:Garden Planner
  • 大模型微调技术 --> LoRA 系列之 QLoRA (省资源能手)
  • 【算法】递归+深搜+哈希表:889.根据前序和后序遍历构造二叉树
  • [原创](Modern C++)现代C++的字符编码迟迟得不到很好地解决(ASCII, ANSI, UNICODE通俗易懂的故事)
  • VSCode 1.82之后的vscode server离线安装
  • ISME Comm | 机器学习和深度学习在微生物组研究中的应用
  • 牛客sql题目总结(1)
  • RK3568平台(基础篇)selinux内核安全
  • JVM基本结构
  • 工业相机常用功能之白平衡及C++代码分享
  • 天锐绿盾加密软件与Ping32全面对比:为您的数据保驾护航,哪款加密工具更适合您?
  • 解析Go切片:为何按值传递时会发生改变?|得物技术
  • Python OpenCV 傅里叶变换
  • 纯血鸿蒙系统 HarmonyOS NEXT自动化测试实践
  • leetcode 3254 长度为 K 的子数组的能量值 I 中等
  • redhat5与ubuntu上Makefile语法区别
  • DevOps业务价值流:架构设计最佳实践
  • 【K8S问题系列】Kubernetes Pod节点CrashLoopBackOff 状态【已解决】
  • 技术干货丨Inspire Cast 如何避免自动网格划分失败?
  • 汽车免拆诊断案例 | 2017款凯迪拉克XT5车组合仪表上的指针均失灵
  • Git+Jenkins基本使用
  • 环保在线监测平台:环境健康云监测,大数据助力生态文明建设
  • 【前端基础】CSS进阶
  • 泷羽sec学习打卡-shodan扫描5