目录
一、设计模式的分类
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 方法可以方便地创建相似的对象。原型模式在需要生成相同或相似配置的对象时非常实用。