1、描述
单例是一种创建型设计模式, 让你能够保证一个类只有一个实例, 并提供一个访问该实例的全局节点。单例拥有与全局变量相同的优缺点。 尽管它们非常有用, 但却会破坏代码的模块化特性。
优点:由于单例模式在内存中只有一个实例,减少了内存开支,特别是一个对象需要频繁的创建、销毁时,而且创建或销毁时性能又无法优化,单例模式的优势就非常明显。
缺点:单例模式一般没有接口,扩展很困难,若要扩展,除了修改代码基本上没有第二种途径可以实现。
单例模式与单一职责原则有冲突。一个类应该只实现一个逻辑,而不关心它是否是单例的,是不是要单例取决于环境,单例模式把“要单例”和业务逻辑融合在一个类中。
2、结构图
3、C++代码
在muduo库中有一个单例类模板,可以参考https://blog.csdn.net/qu1993/article/details/109476614
下面是一个使用互斥锁实现的线程安全的单例类,这个例子是最后提到的网站上的例子,但我觉得这个例子不太好,还是使用pthread_once实现更容易一些,或者干脆使用一个静态变量得了
#include <string>
#include <mutex>
#include <iostream>
#include <thread>
//单例类定义GetInstance替代构造函数,并允许用户反复使用该类的同一实例
class Singleton
{
private:
static Singleton * pinstance_;
static std::mutex mutex_;
//单例的构造函数和析构函数总是定义为私有的,防止直接创建该类的对象
protected:
Singleton(const std::string value): value_(value)
{
}
~Singleton() {}
std::string value_;
public:
//不能使用拷贝构造函数
Singleton(Singleton &other) = delete;
//不能使用赋值运算符
void operator=(const Singleton &) = delete;
//静态方法,提供访问单例的方式。第一次会创建一个单例对象,之后再调用都是返回该对象
static Singleton *GetInstance(const std::string& value);
//业务逻辑
void SomeBusinessLogic()
{
// ...
}
std::string value() const{
return value_;
}
};
Singleton* Singleton::pinstance_{nullptr};
std::mutex Singleton::mutex_;
Singleton *Singleton::GetInstance(const std::string& value)
{
std::lock_guard<std::mutex> lock(mutex_);
if (pinstance_ == nullptr)
{
pinstance_ = new Singleton(value);
}
return pinstance_;
}
void ThreadFoo(){
// 下面的代码模拟缓慢的初始化。
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
Singleton* singleton = Singleton::GetInstance("FOO");
std::cout << singleton->value() << "\n";
}
void ThreadBar(){
// 下面的代码模拟缓慢的初始化。
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
Singleton* singleton = Singleton::GetInstance("BAR");
std::cout << singleton->value() << "\n";
}
int main()
{
std::cout <<"If you see the same value, then singleton was reused (yay!\n" <<
"If you see different values, then 2 singletons were created (booo!!)\n\n" <<
"RESULT:\n";
std::thread t1(ThreadFoo);
std::thread t2(ThreadBar);
t1.join();
t2.join();
return 0;
}
下面这个是我仿照网站上的例子使用pthread_once实现的单例:
#include <string>
#include <iostream>
#include <pthread.h>
//单例类定义GetInstance替代构造函数,并允许用户反复使用该类的同一实例
class Singleton
{
private:
//单例的构造函数和析构函数总是定义为私有的,防止直接创建该类的对象
Singleton() {}
~Singleton() {}
public:
//不能使用拷贝构造函数
Singleton(Singleton &other) = delete;
//不能使用赋值运算符
void operator=(const Singleton &) = delete;
//静态方法,提供访问单例的方式。第一次会创建一个单例对象,之后再调用都是返回该对象
static Singleton &Instance();
//业务逻辑
void SomeBusinessLogic()
{
// ...
}
std::string GetValue() const{
return value_;
}
void SetValue(std::string value) {
value_ = value;
}
private:
static void Init();
private:
std::string value_;
static pthread_once_t ponce_;
static Singleton* instance_;
};
pthread_once_t Singleton::ponce_ = PTHREAD_ONCE_INIT;
Singleton* Singleton::instance_ = NULL;
Singleton &Singleton::Instance()
{
pthread_once(&ponce_, Init);
return *instance_;
}
void Singleton::Init()
{
instance_ = new Singleton();
}
int main()
{
Singleton::Instance().SetValue("hello");
std::cout << Singleton::Instance().GetValue() << std::endl;
}
参考