单例模式
本课属于 Coddy Dart 学习旅程的“面向对象编程”单元。第 90 课,共 110 课。
单例模式可确保一个类在整个应用程序中只有一个实例,并提供全局访问该实例的入口。当系统需要一个对象来协调各项操作时,这种模式就很有用,例如配置管理器、数据库连接或日志服务。
在 Dart 中,你可以将工厂构造函数与私有静态实例结合起来实现单例:
class AppConfig {
static final AppConfig _instance = AppConfig._internal();
String appName = 'MyApp';
String version = '1.0.0';
// 私有命名构造函数
AppConfig._internal();
// 工厂构造函数返回同一个实例
factory AppConfig() {
return _instance;
}
}
void main() {
var config1 = AppConfig();
var config2 = AppConfig();
config1.appName = 'UpdatedApp';
print(config2.appName); // UpdatedApp
print(identical(config1, config2)); // true
}私有构造函数 _internal() 可以防止外部实例化。静态字段 _instance 保存唯一的实例,该实例会在类加载时创建一次。每次调用 AppConfig() 都会返回同一个实例,因此通过一个引用所做的更改在任何地方都可见。
谨慎使用单例,因为它们会引入全局状态,可能让测试变得更困难。它们最适合用于需要在整个应用中保持状态一致的共享资源。
挑战
简单让我们使用单例模式来构建一个游戏设置管理器!你将创建一个系统,确保整个应用中只有一个游戏设置实例,这样游戏的所有部分都能共享相同的配置。
你将把代码整理到两个文件中:
game_settings.dart:创建一个实现单例模式的GameSettings类。你的设置管理器应包含:- 一个私有的静态 final 实例,用于保存唯一的
GameSettings对象 - 一个私有命名构造函数,用于防止外部创建实例
- 一个始终返回同一实例的工厂构造函数
- 三个设置字段:
difficulty(String,默认值:"Normal")、soundEnabled(bool,默认值:true)和playerName(String,默认值:"Player1") - 一个方法
displaySettings(),用于按以下格式打印当前设置:Settings: [playerName] | Difficulty: [difficulty] | Sound: [on/off](如果 soundEnabled 为 true,则打印 "on";如果为 false,则打印 "off")
- 一个私有的静态 final 实例,用于保存唯一的
main.dart:导入游戏设置,并演示单例模式能正常工作:- 获取设置实例,并将其命名为
settings1 - 调用
displaySettings()来显示默认值 - 修改设置:将
playerName改为 "Hero",将difficulty改为 "Hard",并将soundEnabled改为 false - 再获取一个设置引用,并将其命名为
settings2 - 对
settings2调用displaySettings(),以证明它反映了通过settings1所做的更改 - 使用以下格式打印
settings1和settings2是否相同:Same instance: [true/false]
- 获取设置实例,并将其命名为
这展示了单例的核心优势:由于只有一个实例,因此在应用中的任何位置所做的更改都会立即在其他所有位置生效!
预期输出:
Settings: Player1 | Difficulty: Normal | Sound: on
Settings: Hero | Difficulty: Hard | Sound: off
Same instance: true亲手试试
import 'game_settings.dart';
void main() {
// TODO:获取设置实例,并将其命名为 settings1
// TODO:调用 displaySettings() 显示默认值
// TODO:修改设置:
// 将 playerName 改为 "Hero"
// 将 difficulty 改为 "Hard"
// 将 soundEnabled 改为 false
// TODO:获取设置的另一个引用,并将其命名为 settings2
// TODO:通过 settings2 调用 displaySettings(),证明它反映了这些更改
// TODO:输出 settings1 和 settings2 是否是同一个实例
// 格式:Same instance: [true/false]
}
这节课包含一个小测验。开始学习即可作答,并记录你的进度。
面向对象编程中的所有课
自己练习: Dart 在线编译器