设计模式介绍
一、单例模式介绍
1. 单例模式定义
保证一个类仅有一个实例,并提供一个访问它的全局访问点。
2. 单例模式的本质
控制实例的数目
3. 单例模式的结构和说明
(1) 结构
Singleton:负责创建 Singleton类自己的唯一实例,并提供一个 getinstance I的方法,让外部来访问这个类的唯一实例。
(2) 调用顺序
懒汉式
饿汉式
4. 单例模式适用情况
当需要控制一个类的实例只能有一个,而且客户只能从一个全局访问点访问它时,可以选用单例模式,这些功能恰好是单例模式要解决的问题。
5. 单例模式优缺点
- 时间和空间
懒汉式典型的时间换空间, 饿汉式典型的空间换时间
懒汉式是典型的时间换空间,也就是每次获取实例都会进行判断,看是否需要创建实例,浪费判断的时间。当然,如果一直没有人使用的话,那就不会创建实例,则节约内存空间。
饿汉式是典型的空间换时间,当类装载的时候就会创建类实例,不管你用不用,先创建出来,然后每次调用的时候,就不需要再判断了,节省了运行时间。
- 线程安全
不加同步的懒汉式是线程不安全的, 饿汉式是线程安全的
当然懒汉式也是可以实现线程安全的, 可以采取双重加锁检查的方法
6. 相关模式
很多模式都可以使用单例模式,只要这些模式中的某个类,需要控制实例为一个的时候,就可以很自然地使用上单例模式。比如抽象工厂方法中的具体工厂类就通常是个单例
二、单例模式示例代码
这里只介绍比较常见的经典方式,其他奇淫巧技不做介绍
1. 懒汉式
#include <iostream>
#include <string>
#include <memory>
#include <mutex>
using namespace std;
template <typename T>
class Singleton{
public:
template <typename... Args>
static T* Instance(Args&&... args){
if(m_instance == nullptr){
std::unique_lock<std::mutex> lock(mutex);
if(m_instance == nullptr){
m_instance = new T(std::forward<Args>(args)...);
}
}
return m_instance;
}
Singleton() = delete;
Singleton(const Singleton&) = delete;
Singleton& operator=(const Singleton&) = delete;
Singleton(Singleton&&) = delete;
Singleton& operator=(Singleton&&) = delete;
private:
static T* m_instance;
std::mutex;
};
template <typename T> T* Singleton<T>::m_instance = nullptr;
//test
struct A
{
A(const string&){cout<<"lvaue"<<endl;}
A(string&& x){cout<<"rvaue"<<endl;}
};
struct B
{
B(const string&){cout<<"lvaue"<<endl;}
B(string&& x){cout<<"rvaue"<<endl;}
};
struct C
{
C(int x, double y){}
void Fun(){cout<<"test"<<endl;}
};
int main(){
string str = "bb";
//创建A类型的单例
Singleton<A>::Instance(str);
//创建B类型的单例,临时变量str被move之后变成右值,然后可以根据移动语义来避免复制
Singleton<B>::Instance(std::move(str));
// 创建C类型的单例,含两个参数
Singleton<C>::Instance(1, 3.14)->Fun();
return 0;
}
2. 饿汉式
#include <iostream>
#include <string>
#include <memory>
using namespace std;
template <typename T>
class Singleton{
public:
static T* Instance(){
return &m_instance;
}
Singleton() = delete;
Singleton(const Singleton&) = delete;
Singleton& operator=(const Singleton&) = delete;
Singleton(Singleton&&) = delete;
Singleton& operator=(Singleton&&) = delete;
private:
static T m_instance;
};
template <typename T> T Singleton<T>::m_instance;
struct A
{
A() = default;
void Fun(){std::cout<<"A::Fun"<<std::endl;};
};
struct B
{
B() = default;
void Fun(){std::cout<<"B::Fun"<<std::endl;};
};
int main(){
Singleton<A>::Instance()->Fun();
Singleton<B>::Instance()->Fun();
return 0;
}
3. 静态局部变量式
#include <iostream>
#include <string>
#include <memory>
using namespace std;
template <typename T>
class Singleton{
public:
template <typename... Args>
static inline T& GetInstance(Args&&... args){
static T obj {std::forward<Args>(args)...};
return obj;
}
template <typename ... Args>
static inline T* GetInstancePtr(Args... args){
return &GetInstance(args...);
}
Singleton() = delete;
Singleton(const Singleton&) = delete;
Singleton& operator=(const Singleton&) = delete;
Singleton(Singleton&&) = delete;
Singleton& operator=(Singleton&&) = delete;
};
//test
struct A
{
A(const string&){cout<<"lvaue"<<endl;}
A(string&& x){cout<<"rvaue"<<endl;}
};
struct B
{
B(const string&){cout<<"lvaue"<<endl;}
B(string&& x){cout<<"rvaue"<<endl;}
};
struct C
{
C(int x, double y){}
void Fun(){cout<<"test"<<endl;}
};
int main(){
string str = "bb";
//创建A类型的单例
Singleton<A>::GetInstance(str);
//创建B类型的单例,临时变量str被move之后变成右值,然后可以根据移动语义来避免复制
Singleton<B>::GetInstance(std::move(str));
// 创建C类型的单例,含两个参数
auto ptr = Singleton<C>::GetInstancePtr(1, 3.14);
// 获取单例并调用单例对象的方法
ptr->Fun();
return 0;
}