核心思想为:确保一个类只有一个实例,而且自行实例化并向整个系统提供这个实例。
单例模式最佳实践是无状态的,比如以工具类的形式提供。
要求构造方法是private的,并且拥有一个当前类的静态成员变量,一个静态方法用于向外界提供当前类的实例。
一个简单的单例模式如下所示:
class Singleton{
private:
Singleton(){}
static Singleton singleton;
public:
static Singleton getInstance() {
return singleton;
}
};
/*
实例化时机:饿汉式、懒汉式
饿汉式:
static Singleton singleton = new Singleton(); // 在类进行加载的时候立刻进行实例化
懒汉式:注意在这里需要进行同步处理。加锁,来防止它被多次实例化
synchronized static Singleton getInstance() {
if(singleton = NULL) singleton = new Singleton();
return singleton;
} // 在第一次使用的时候进行实例化
*/
懒汉式实例化的双重检查锁实现:
package interview.pattern;
public class SingletonPattern {
public static void main(String[] args){
}
}
class Singleton{
private:
Singleton(){}
volatile static Singleton singleton;
public:
synchronized static Singleton getInstance() {
if(singleton = null) {
synchronized (Singleton.class) {
if(singleton == null)
singleton = new singleton();
}
return singleton;
}
};
双重检查锁的实现up评论区有说明:五分钟学设计模式.01.单例模式_哔哩哔哩_bilibili
要加 volatile 修饰,singleton = new Singleton() 可以拆解为3步:
1、分配内存,
2、初始化对象,
3、指向刚分配的地址,
但是2和3由于cpu的优化,可能会发生重排序。若发生重排序,假设 A 线程执行了1和3,还没有执行2,B线程来到判断 NULL,B线程就会直接返回还没初始化的instance了。volatile
可以避免重排序。
那么为什么volatile
可以避免重排序呢?
在C++中,volatile
关键字是用来告诉编译器一个变量的值可能会在任何时候被外部因素改变,因此编译器在优化代码时需要特别对待这些变量。具体的可以去搜搜,我就不记下来了。
例题
【设计模式专题之单例模式】1.小明的购物车 (kamacoder.com)
#include <iostream>
#include <string>
#include <unordered_map>
#include <vector>
class ShoppingCart {
private:
std::unordered_map<std::string, int> goodlist; // 购物车信息
std::vector<std::string> orderlist; // 商品清单
// 私有化构造函数和析构函数,确保外部无法直接实例化和销毁对象
ShoppingCart() {}
~ShoppingCart() {}
public:
// 获取单例实例的静态方法
static ShoppingCart& getInstance() {
static ShoppingCart instance; // 在第一次调用时初始化,确保唯一性
return instance;
}
// 获取购物车信息的方法
std::unordered_map<std::string, int>& getGoodList() {
return goodlist;
}
// 获取商品清单的方法
std::vector<std::string>& getOrderList() {
return orderlist;
}
// 添加商品到购物车
void addGoods(const std::string& good_name, int good_num) {
goodlist[good_name] = good_num;
orderlist.push_back(good_name);
}
};
int main() {
ShoppingCart& sc = ShoppingCart::getInstance(); // 获取 ShoppingCart 的单例实例
std::string good_name;
int good_num;
// 输入商品信息,直到输入结束
while (std::cin >> good_name >> good_num) {
sc.addGoods(good_name, good_num); // 使用公有成员函数来添加商品到购物车
}
// 输出购物车信息
for (const auto& item : sc.getOrderList()) {
std::cout << item << " " << sc.getGoodList()[item] << std::endl;
}
return 0;
}
参考资料:
五分钟学设计模式.01.单例模式_哔哩哔哩_bilibili
代码随想录的讲解:卡码网KamaCoder
除此之外还建议看看侯捷的讲解