设计模式小案例之单例

99 阅读3分钟

单例

单例模式是一种广泛使用的设计模式,特别适用于需要全局访问的场景。 在应用开发中,像网络请求管理、应用配置、数据库操作以及本地存储等 通常需要确保只有一个全局对象实例进行操作,因此非常适合采用单例模式来实现。

单例模式的两种创建方式

懒汉模式

而懒汉比较懒,只有当调用getInstance的时候,才回去初始化这个单例。

优点

不使用则不创建,节省资源

缺点

第一次使用时需要初始化,可能有延迟 基本实现不是线程安全的,需要额外处理,等待同步的问题。

实例

class SingletonLH {
static SingletonLH? instance;

SingletonLH._();

static SingletonLH getInstance() {
instance ??= SingletonLH._();
return instance!;
}
}

饿汉模式

饿汉就是类一旦加载,就把单例初始化完成,保证getInstance的时候,单例是已经存在的了。

优点

获取实例时速度快,没有延迟 天然线程安全,因为实例在类加载时就创建完成

缺点

在类加载时就创建实例,不管是否使用

实例

class SingletonEH {
static SingletonEH instance = SingletonEH._();


SingletonEH._();

static SingletonEH getInstance() {
return instance;
}
}

适用场景

懒汉式适用于:
  • 实例化成本高的情况
  • 不确定是否会使用该实例的情况
  • 资源敏感的应用
饿汉式适用于:
  • 实例化成本较低的情况
  • 确定会使用该实例的情况
  • 需要确保绝对的线程安全的情况

小案例

需求描述

游戏在任何时候都只能有一个活跃的进度管理器实例。

进度管理器需要在游戏的不同部分之间共享数据。

它应该能保存和加载游戏进度。

进度管理器应该提供方法来更新和查询玩家的各种统计数据。

系统需要线程安全,因为可能会有多个游戏系统同时访问或修改数据。

使用单例模式实现这个游戏进度管理器。你需要:

在这个类中实现以下功能:

保存玩家的等级、经验值、生命值等基本属性

管理已完成的任务列表

管理玩家的物品清单

提供保存和加载游戏进度的方法

实现更新和查询这些数据的方法

创建单例

创建单例就非常简单了,我们选择饿汉模式来创建

class GameProgressManager {
static GameProgressManager instance = GameProgressManager._();

GameProgressManager._();

//使用工厂构造确保返回同一个实例
factory GameProgressManager() {
return instance;
}
//亦可以通过get获取这个实例
// static GameProgressManager get instance => _instance;
}

定义玩家属性

int _playerLevel = 1; //等级
int _experienceValue = 0;//经验
int _healthValue = 100;//生命值
double _gameProgress = 0.0; //经验
final List<String> _items = []; // 物品

管理玩家属性

int get playerLevel => _playerLevel;
set playerLevel(int value) {
if (value != _playerLevel) {
_playerLevel = value;
}
}

int get experienceValue => _experienceValue;
set experienceValue(int value) {
if (value < 0) throw ArgumentError('经验值不能为负数');
_experienceValue = value;
_checkLevelUp();  // 检查是否需要升级
}

int get healthValue => _healthValue;
set healthValue(int value) {
if (value < 0) {
_healthValue = 0;
} else if (value > 100) {
_healthValue = 100;
} else {
_healthValue = value;
}
}

double get gameProgress => _gameProgress;
set gameProgress(double value) {
if (value < 0 || value > 100) {
throw ArgumentError('进度必须在0-100之间');
}
_gameProgress = value;
}

// 9. 物品管理方法
List<String> get items => List.unmodifiable(_items);

void addItem(String item) {
if (item.isNotEmpty && !_items.contains(item)) {
_items.add(item);
}
}

void removeItem(String item) {
_items.remove(item);
}


void _checkLevelUp() {
final newLevel = (_experienceValue / 1000).floor() + 1;
if (newLevel != _playerLevel) {
playerLevel = newLevel;
}
}

总结

如果程序中的某个类对于所有客户端只有一个可用的实例,可以使用单例模式。