第十八章、设计模式
设计模式(Design Pattern)是软件工程中被多数人总结出来的一套软件设计经验。它是一套成熟的方案,可以在某些应用场合直接拿来借鉴。
常见的设计模式有:单例模式、工厂模式、观察者模式等。
1. 单例模式
单例模式(Singleton Pattern)用于在确保一个类在整个程序运行期间,有且仅有一个实例(对象)存在,并提供一个全局访问点来获取它的设计模式。
使用 C++ 语言实现单例模式有两种实现方法:
- 饿汉式(提前初始化)
- 懒汉式
1. 饿汉式
饿汉式指在类加载时(main 调用前)就立即创建好实例(对象),之后则禁止再创建新实例的实现方式。
饿汉式的优点是写法简单、线程安全(无需加锁);缺点是即使你暂时没用它,它也会占用内存。
示例:
使用饿汉式方式创建 Singleton 类型的单例。
// filename: singleton1.cpp
class Singleton {
public:
// 获取单例的接口函数
static Singleton &getInstance() {
return s_instance;
}
public:
void do_things(void) {
// 单例做事情的成员函数
}
private:
Singleton() = default; // 私有全部构造函数
// 删除拷贝构造、拷贝赋值、移动构造、移动赋值
Singleton(const Singleton&) = delete;
Singleton& operator=(const Singleton&) = delete;
Singleton(const Singleton&&) = delete; // C++11或之后版本
Singleton& operator=(const Singleton&&) = delete; // C++11或之后版本
private:
static Singleton s_instance;
};
// 创建单例
Singleton Singleton::s_instance;
int main(int argc, char * argv[]) {
// 用法
Singleton &s(Singleton::getInstance());
s.do_things();
return 0;
}
2. 懒汉式
懒汉式指在程序第一次调用 getInstance() 来获取实例(对象)时才创建实例(对象),之后则禁止再创建新实例的实现方式。
懒汉式的优点启动时不占用内存,只有在需要时才动态创建实例(对象);缺点是如果多线程同时调用 getInstance() 来获取实例,可能会同时创建多个对象,需要加锁来对创建对象的临界区进行保护。好有一个缺点是需要手动释放单例对象。
示例:
使用懒汉式 方式创建 Singleton 类型的单例。
// filename: singleton2.cpp
#include <mutex>
class Singleton {
public:
// 获取单例的接口函数
static Singleton &getInstance() {
if (nullptr == instance) {
std::lock_guard<std::mutex> lock(mtx);
if (instance == nullptr) { // 第二次检查
instance = new Singleton();
}
}
return *instance;
}
public:
void do_things(void) {
// 单例做事情的成员函数
}
private:
Singleton() = default; // 私有全部构造函数
// 删除拷贝构造、拷贝赋值、移动构造、移动赋值
Singleton(const Singleton&) = delete;
Singleton& operator=(const Singleton&) = delete;
Singleton(const Singleton&&) = delete; // C++11或之后版本
Singleton& operator=(const Singleton&&) = delete; // C++11或之后版本
private:
static Singleton *instance;
static std::mutex mtx;
};
// 初始化静态成员
Singleton * Singleton::instance = nullptr;
std::mutex Singleton::mtx;
int main(int argc, char * argv[]) {
// 用法
Singleton &s(Singleton::getInstance());
s.do_things();
return 0;
}