設計模式之單例模式

進擊的汪sir 2021-08-15 18:17:24 阅读数:744

本文一共[544]字,预计阅读时长:1分钟~
模式 模式

1. 單例模式

1.1 簡介

在實際項目開發中肯定會有這麼一種情况,一個類只能有一個對象被創建,如果有多個對象的話, 可能會導致狀態的混亂和不一致。這種情况下,單例模式是最恰當的解决辦法。 它有很多種實現方式,各自的特性不相同,使用的情形也不相同。

1.2 特點

1.提供了一個對對象的全局訪問指針

2.在不影響單例類的客戶端的情况下允許將來有多個實例,通過接口獲得

3.確保一個類只有一個實例被建立 ,不能額外創建一個新的對象

1.3 應用場景

  • 讀取配置文件,讀取的配置文件都是公用的,只能有一個示例去操作文件

  • 數據連接線程池,多線程的時候.

  • 應用程序的日志應用,一般都可以使用單例模式來實現,只能又一個示例去操作文件

1.4 實現思路

1)將構造函數的訪問權限修改為private或protected,不允許類的外部來創建對象

2)用一個靜態成員指針指向創建的對象

3)提供一個靜態成員函數,獲得這個對象的首地址

2. 懶漢式

先上代碼:

#include <iostream>
using namespace std;
// 作者博客
static string myblog = "https://www.cnblogs.com/wanghongyang/";
class singelton {
private:
singelton() { ; }
static singelton *single;
public:
static singelton *get_instance();
};
// 靜態變量初始化
singelton* singelton::single = NULL;
singelton * singelton::get_instance()
{
if (single == NULL) {
single = new singelton;
}
return single;
}
int main()
{
singelton* s1 = singelton::get_instance();
singelton* s2 = singelton::get_instance();
if (s1 == s2)
{
cout << "s1==s2" << endl;
}
else {
cout << "s1!=s2" << endl;
}
return 0;
}

可以看到,思路是非常簡單的,所謂懶漢式,就是當你用的時候,我才初始化

但是這會帶來一個問題,大家思考一下,如果添加了析構函數將會怎麼樣,如何解决?

參考代碼如下

class singelton {
private:
singelton() { ; }
static singelton *single;
public:
static singelton *get_instance();
~singelton() {
cout << "~singelton()" << endl;
if (single != NULL)
{
delete single;
}
}
};
// 靜態變量初始化
singelton* singelton::single = NULL;
singelton * singelton::get_instance()
{
if (single == NULL) {
single = new singelton;
}
return single;
}
int main()
{
singelton* s1 = singelton::get_instance();
singelton* s2 = singelton::get_instance();
if (s1 == s2)
{
cout << "s1==s2" << endl;
}
else {
cout << "s1!=s2" << endl;
}
delete s1;
return 0;
}

可以看到,會出現不斷調用析構函數的現象,因為singelton為用戶自定義的類,delete會默認調用該類的析構函數

運行結果:

image-20210815114706320

2.1 解决方案

自定義一個類,用於釋放空間

class singelton {
private:
singelton() { ; }
static singelton *single;
class DeleteSpace {
public:
DeleteSpace();
~DeleteSpace();
};
static DeleteSpace ds; // 釋放堆區空間的類對象
public:
static singelton *get_instance();
};
// 靜態變量初始化
singelton* singelton::single = NULL;
singelton * singelton::get_instance()
{
if (single == NULL) {
single = new singelton;
}
return single;
}
singelton::DeleteSpace singelton::ds; // 初始化釋放空間的靜態類
singelton::DeleteSpace::DeleteSpace() { ; }
singelton::DeleteSpace::~DeleteSpace() {
cout << "~DeleteSpace()" << endl;
if (single != NULL)
{
delete single;
}
}
int main()
{
singelton* s1 = singelton::get_instance();
singelton* s2 = singelton::get_instance();
if (s1 == s2)
{
cout << "s1==s2" << endl;
}
else {
cout << "s1!=s2" << endl;
}
return 0;
}

這個例子的原理就是,當程序運行結束,堆區釋放的時候,會自動調用析構函數,析構單例類,這樣做就不需要手動的去釋放單例類

運行結果

image-20210815155954306

2.2 優缺點

優點:

在使用的時候,才會分配內存,創建對象

缺點:

在多線程使用,會出現創建多個對象的問題,線程不安全

2.3 線程安全示例代碼

在剛剛的那種懶漢式的方法中,如果有多線程的情况,可能會大家都以為自己是第一個創建單例類,因此有可能創建多個單例類,為了保證線程安全,下面演示線程不安全的代碼

image-20210815180411067

image-20210815180426525

結果可以看到,調用了三次構造函數

image-20210815180452770

解决辦法

添加互斥鎖來解决

image-20210815180521228

image-20210815180532387

3. 餓漢式

在單例類定義的時候就進行了實例化。---在類定義的時候,分配空間

image-20210815180739253

3.1 優缺點

優點: 線程安全

缺點:還沒有正式使用,就分配了內存空間,浪費了內存

版权声明:本文为[進擊的汪sir]所创,转载请带上原文链接,感谢。 https://gsmany.com/2021/08/20210815181706326U.html