前言
我们都知道设计模式是相同的,同一种设计模式的理念不会因为语言不同而会有所改变,但是由于语法的差异,设计模式的写法也有所差异,本文会介绍一些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. 饿汉式单例
这种方式在类加载时就创建实例,线程安全,但如果实例初始化开销大且不一定会用到,会造成资源浪费。
dart
class Singleton {
//私有构造函数
Singleton._privateConstructor();
// 静态实例
static final Singleton instance = Singleton._privateConstructor();
// 内部方法
void printHello() {
print('Hello');
}
}
//调用方式
Singleton.instance.printHello();
2. 懒汉式单例
这种方式在第一次使用时才创建实例,延迟加载。
dart
class SingletonLazy {
//私有构造
SingletonLazy._privateConstructor();
//静态实例
static SingletonLazy? _instance;
//获取实列方法
static SingletonLazy getInstance() {
if (_instance == null) {
_instance = SingletonLazy._privateConstructor();
}
return _instance!;
}
}
也可以通过dart中的工厂类来创建懒汉式
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 的静态内部类特性,既实现了延迟加载,又保证了线程安全。
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)是一种创建型设计模式,用于定义一个接口或抽象类以创建对象,但让子类决定要实例化的类。工厂模式可以将实例化对象的逻辑与使用对象的逻辑分离,提高代码的可扩展性和可维护性。
像支付(不同的支付类型)、日志、等都可以使用该模式
工厂模式的主要分类
- 简单工厂模式: 提供一个创建对象实例的方法,根据传入的参数决定创建哪种类型的对象。
- 抽象工厂模式:提供一个接口,用于创建相关或依赖对象的家族,而无需明确指定具体类。
简单工厂模式
简单工厂模式通过一个静态方法创建对象实例。
dart
//对象实例子
abstract class Shape {
void draw();
}
//实现抽象方法,重写自己的实例子
class Circle implements Shape {
@override
void draw() {
print("Drawing a Circle");
}
}
class Square implements Shape {
@override
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
}
抽象工厂模式
抽象工厂模式用于创建相关或依赖对象的家族。
dart
abstract class Button {
void paint();
}
class WindowsButton implements Button {
@override
void paint() {
print("Rendering a button in Windows style");
}
}
class MacOSButton implements Button {
@override
void paint() {
print("Rendering a button in MacOS style");
}
}
abstract class GUIFactory {
Button createButton();
}
class WindowsFactory implements GUIFactory {
@override
Button createButton() {
return WindowsButton();
}
}
class MacOSFactory implements GUIFactory {
@override
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): 维护对策略对象的引用,并在需要时调用策略对象的方法。
我们以用算不同类型的折扣为例。策略模式可以帮助我们在不同的折扣计算方法之间切换。
- 定义策略接口
首先,定义一个策略接口,描述不同折扣算法的通用方法。
dart
abstract class DiscountStrategy {
//计算折扣金额
double calculateDiscount(double price);
}
2. 实现具体策略
为不同的折扣类型算法的具体的策略类。
dart
//无折扣
class NoDiscountStrategy implements DiscountStrategy {
@override
double calculateDiscount(double price) {
return 0.0;
}
}
//具体折扣
class PercentageDiscountStrategy implements DiscountStrategy {
final double percentage;
PercentageDiscountStrategy(this.percentage);
@override
double calculateDiscount(double price) {
return price * (percentage / 100);
}
}
//全免
class FixedAmountDiscountStrategy implements DiscountStrategy {
final double discountAmount;
FixedAmountDiscountStrategy(this.discountAmount);
@override
double calculateDiscount(double price) {
return discountAmount;
}
}
3. 创建上下文
定义一个上下文类(Context),用于持有策略对象,并在需要时调用策略的方法。
dart
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. 使用策略模式
现在可以在应用程序中使用策略模式,根据不同的需求动态选择折扣策略。
dart
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. 定义产品
首先,定义需要创建的复杂对象(对象参数比较多,或者链路很长)。
dart
class ComplexWidget {
String? title;
String? imageUrl;
String? description;
@override
String toString() {
return 'ComplexWidget(title: $title, imageUrl: $imageUrl, description: $description)';
}
}
2. 定义建造者接口
定义一个接口,描述创建产品的步骤。
dart
abstract class ComplexWidgetBuilder {
void setTitle(String title);
void setImageUrl(String imageUrl);
void setDescription(String description);
ComplexWidget getResult();
}
3. 实现具体建造者
实现建造者接口,提供具体的构建步骤。
dart
class ConcreteComplexWidgetBuilder implements ComplexWidgetBuilder {
final ComplexWidget _complexWidget = ComplexWidget();
@override
void setTitle(String title) {
_complexWidget.title = title;
}
@override
void setImageUrl(String imageUrl) {
_complexWidget.imageUrl = imageUrl;
}
@override
void setDescription(String description) {
_complexWidget.description = description;
}
@override
ComplexWidget getResult() {
return _complexWidget;
}
}
4. 定义指挥者
定义一个指挥者类,用于控制构建过程。
dart
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. 使用建造者模式
在应用程序中使用建造者模式来创建复杂对象。
dart
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.)
}
未完待续
后面慢慢会把常用的设计模式都在这里做更新。。。
每个设计模式都有自己的优缺点,其实适合自己的才是最合理的,不要为了设计代码而设计代码,如果不理解业务场景强上设计模式,只会让代码写的更复杂