构造函数类型
1. 默认构造函数
class MyClass {
MyClass() {
// 初始化代码
}
}
2. 命名构造函数
class MyClass {
MyClass.myNamedConstructor() {
// 初始化代码
}
}
// 调用
var myObject = MyClass.myNamedConstructor();
3. 工厂构造函数
class MyClass {
factory MyClass() {
return MyClass._internal();
}
MyClass._internal() {
// 初始化代码
}
}
4. 常量构造函数
class MyClass {
final int value;
const MyClass(this.value);
}
单例
1. 饿汉式单例
class Singleton {
// 静态实例,立即初始化
static final Singleton _instance = Singleton._internal();
// 私有构造函数
Singleton._internal();
// 提供一个全局访问点
factory Singleton() {
return _instance;
}
}
-
优点
实现简单:代码简洁,易于理解。
线程安全:由于实例在类加载时创建,天然具备线程安全性。 -
缺点
资源浪费:实例在类加载时就创建,即使从未使用过该实例,也会占用内存。
缺乏灵活性:没有延迟加载的优势。
2. 懒汉式单例 (Lazy Initialization)
class Singleton {
static Singleton? _instance;
// 私有构造函数
Singleton._internal();
// 提供一个全局访问点
factory Singleton() {
_instance ??= Singleton._internal();
return _instance!;
}
}
-
优点
延迟加载:只有在第一次使用时才创建实例,节省内存。
实现简单:代码相对简单。 -
缺点
线程不安全:在多线程环境下可能会创建多个实例,需要额外的同步机制确保线程安全。
3. 使用 Dart 的静态变量
class Singleton {
// 静态实例,立即初始化
static final Singleton instance = Singleton._internal();
// 私有构造函数
Singleton._internal();
}
-
优点
实现简单:代码极其简洁,易于理解。
线程安全:由于实例在类加载时创建,天然具备线程安全性。 -
缺点
资源浪费:实例在类加载时就创建,即使从未使用过该实例,也会占用内存。
缺乏灵活性:没有延迟加载的优势。
4. 使用 get 方法懒加载
class Singleton {
static Singleton? _instance;
Singleton._internal();
static Singleton get instance {
_instance ??= Singleton._internal();
return _instance!;
}
}
-
优点
延迟加载:只有在第一次使用时才创建实例,节省内存。
实现简单:代码相对简单。 -
缺点
线程不安全:在多线程环境下可能会创建多个实例,需要额外的同步机制确保线程安全。
5. 使用 Dart 的 late 关键字(推荐)
class Singleton {
static late final Singleton _instance = Singleton._internal();
Singleton._internal();
static Singleton get instance => _instance;
}
-
优点
延迟加载:只有在第一次访问时才初始化实例,节省内存。
线程安全:Dart 的 late 关键字确保实例只被初始化一次,天然线程安全。 -
缺点
语言特性依赖:需要 Dart 2.12 及以上版本支持 late 关键字。
单例实现方案 比较总结
饿汉式单例 适用于应用启动时就需要实例,并且实例创建开销不大的场景。
懒汉式单例 适用于实例创建开销较大,且可能并不总是需要实例的场景,但需要注意线程安全。
静态变量单例 适用于实例创建开销不大,且需要简单实现的场景。
get 方法懒加载 适用于需要延迟加载且愿意在实现中做一些妥协的场景。
late 关键字 是现代 Dart 中推荐的方式,结合了延迟加载和线程安全的优势。