1. 程式人生 > >單例模式--含義是某一個類,在一個程序中只有唯一的一個物件

單例模式--含義是某一個類,在一個程序中只有唯一的一個物件

###單例模式
單例模式是一種常見的設計模式
表示的含義是某一個類,在一個程序中只有唯一的一個物件,並且在語法角度上進行制約

###為什麼要有單例模式 在系統中,有些類必須保證只能創造出一個物件 我們windows系統中,只能開啟一個資源管理器,因為若是可以開啟多個資源管理器視窗,就會存在這樣的問題: 1.若這些視窗中顯示的內容是均相同的,這是一種資源的浪費 2.若這些視窗中顯示的內容是不相同的,那麼到底哪一個才是正真反應出當前的各個任務狀態呢?或者說同一時刻存在兩種不同的狀態,這怕是與實際不相符吧 ###單例模式要點
  • 一個類只能例項化出一個物件
  • 必須由自己進行建立
  • 它必須向整個系統提供訪問介面
###單例模式的實現

(方案一)餓漢模式

物件定義後資料立即載入到記憶體,以空間換時間的做法

class Singleton_1                                                                                                                                              
{                                                                                                                                                              
  public:                                                                                                                                                      
    static Singleton_1 *GetInstance()//靜態的成員函式,為外部提供介面                                                                                       
    {                                                                                                                                                          
      return _inst;                                                                                                                                            
    }
  protected:
	  Singleton_1() {};                                                                                                                                                            
  private:                                                                                                                                                                                                                                                                                         
    Singleton_1(const Singleton_1 & ) = delete;                                                                                                                
    Singleton_1 operator = (const Singleton_1 &) = delete;                                                                                                     
    static Singleton_1  *_inst;//靜態資料員。在該類範圍中只能定義一個                                                                                                                                                                                                                                                                                             
};                                                                                                                                                             
                                                                                                                                                               
//需要先對靜態成員進行初始化                                                                                                                                   
Singleton_1  *Singleton_1:: _inst =  new Singleton_1();                                                                                                        
//得到唯一的物件                                                                                                                                               
Singleton_1 * inst_ptr = Singleton_1::GetInstance();  

舉例驗證

#include <stdio.h>
#include <iostream>
using namespace std;

template <class T>                                                                                                                                             
//類模板                                                                                                                                                       
class Singleton_1                                                                                                                                              
{                                                                                                                                                              
  public:                                                                                                                                                      
    static T *GetInstance()//靜態的成員函式,用於訪問 T 資料                                                                                                   
    {                                                                                                                                                          
      return _inst;                                                                                                                                            
    }                                                                                                                                                          
                                                                                                                                                               
  private:                                                                                                                                                     
    Singleton_1(const T & ) = delete;                                                                                                                          
    Singleton_1 & operator = (const T &) = delete;                                                                                                             
    static T* _inst;//靜態資料員。在該類範圍中只能定義一個                                                                                                     
  protected:                                                                                                                                                   
    Singleton_1() {};                                                                                                                                             
    //建構函式設為保護的是為了繼承下去                                                                                                                       
    //這裡採用靜態成員意為 定義多個Signleton物件只能定義出一個T物件                                                                                            
};                                                                                                                                                             
                                                                                                                                                               
                                                                                                                                                               
//需要先對靜態成員進行初始化                                                                                                                                   
template<class T>                                                                                                                                              
T *Singleton_1<T>:: _inst = new T();                                                                                                                           
//規定 T 類物件只能通過 Signleton物件定義出來                                                                                                                  
//獲得唯一的物件                                                                                                                                               
int main()                                                                                                                                                     
{                                                                                                                                                              
  int * ret_ptr_1 = Singleton_1<int>::GetInstance();                                                                                                           
  int * ret_ptr_2 = Singleton_1<int>::GetInstance();                                                                                                           
  *ret_ptr_2 = 9;                                                                                                                                              
  *ret_ptr_1 = 8;                                                                                                                                              
  printf("ret_1 :%d\n",*ret_ptr_1);                                                                                                                            
  printf("ret_2 :%d\n",*ret_ptr_2);                                                                                                                            
  printf("ret_ptr_1 :%p\n",ret_ptr_1);                                                                                                                         
  printf("ret_ptr_2 :%p\n",ret_ptr_2);                                                                                                                         
  return 0;                                                                                                                                                    
}                 

結果顯示:

ret_1 :8
ret_2 :8
ret_ptr_1 :0x12c7c20
ret_ptr_2 :0x12c7c20

餓漢模式是一種執行緒安全的模式

(方案二)懶漢模式

物件定義出來 先不著急載入到記憶體,等到第一次使用的時候,再將資料載入到記憶體,以時間換空間的做法,其實也是一種延時載入

class Singleton_2                                                                                                                                              
{                                                                                                                                                              
  public:                                                                                                                                                      
    static Singleton_2 *GetInstance()                                                                                                                          
    {                                                                                                                                                          
      if(_inst == NULL)                                                                                                                                        
      {//定義的時候先沒有開闢空間,只有在用的時候進行呼叫                                                                                                      
        //多次呼叫的時候,若不為空可以直接返回                                                                                                                 
        _inst = new Singleton_2();                                                                                                                             
      }                                                                                                                                                        
      return _inst;                                                                                                                                            
    };                                                                                                                                                         
  protected:                                                                                                                                                   
    Singleton_2(){};                                                                                                                                             
  private:                                                                                                                                                     
    static Singleton_2 * _inst;                                                                                                                                
    Singleton_2(const Singleton_2 &) = delete; //防止拷貝                                                                                                      
    Singleton_2 operator = (const Singleton_2 &) = delete; //防止賦值                                                                                          
};                                                                                                                                                             
                                                                                                                                                               
//靜態成員需要先進行初始化為NULL                                                                                                                               
Singleton_2 * Singleton_2::_inst = NULL;                                                                                                                       
                                                                                                                                                               
Singleton_2 * inst_ptr= Singleton_2::GetInstance();           

##注意

  1. 這種懶漢單例模式並不是一個執行緒安全模式,因為在判斷_inst是否為空和開闢空間並不是原子操作
  2. 若是兩個執行緒都執行到判斷這一步,就會建立兩個物件,就會出現邏輯錯誤
  3. 所以要在判斷和建立物件時加上互斥鎖
  4. 有為了效率問題,我們只需要在_inst為空的時候再進行加鎖
  5. 又為了防止編譯器過度優化,我們確保每次判斷的時候值都是從記憶體中讀取的,我們需要對私有成員加上 volatile關鍵字

(方案三)執行緒安全的懶漢模式


//執行緒安全的機制的懶漢模式

class Singleton_3
{
  public:
    static pthread_mutex_t lock;

    volatile  static Singleton_3 * GetInstance()
    {
      if(_inst == NULL)
      {
        //每次先判斷為空,即還有沒開闢空間的時候,在實施執行緒安全的措施
        //否則的話,每一次呼叫函式的的時候都判斷就太浪費資源了
        pthread_mutex_lock(&lock);
        if(_inst == NULL)
        {
          _inst = new Singleton_3();
        }
        pthread_mutex_unlock(&lock);
      }
      return  _inst;
    }

  protected:
    //在建構函式種對互斥鎖進行初始化
    Singleton_3()
    {
      pthread_mutex_init(&lock,NULL);
    };
  private:
    volatile static  Singleton_3 * _inst;
    //防止編譯器進行優化
    Singleton_3(const Singleton_3 &) = delete;
    Singleton_3 * operator =(const Singleton_3 &) = delete;
};

//對靜態成員的初始化
pthread_mutex_t Singleton_3:: lock ;
volatile Singleton_3 * Singleton_3:: _inst = NULL;


int main()
{
  volatile Singleton_3 * ret_ptr_1  = Singleton_3 ::GetInstance();
  volatile Singleton_3 * ret_ptr_2  = Singleton_3 ::GetInstance();
  volatile Singleton_3 * ret_ptr_3  = Singleton_3 ::GetInstance();

  printf("ret_ptr_1 :%p\n",ret_ptr_1);
  printf("ret_ptr_2 :%p\n",ret_ptr_2);
  printf("ret_ptr_3 :%p\n",ret_ptr_3);

  return 0;
}

結果:

ret_ptr_1 :0xbadc20
ret_ptr_2 :0xbadc20
ret_ptr_3 :0xbadc20

相關推薦

模式寫MySQL model簡單的增、刪、改、查

單例模式的用途,可用於資料庫操作 <?php Class Db { static private $whe;//條件 static private $tab;//表名 static private $lim;//分段變數 static private $ord

模式--含義一個一個程序只有唯一一個物件

###單例模式 單例模式是一種常見的設計模式 表示的含義是某一個類,在一個程序中只有唯一的一個物件,並且在語法角度上進行制約 ###為什麼要有單例模式 在系統中,有些類必須保證只能創造出一個物件 我們windows系統中,只能開啟一個資源管理器,因為若是可以開

三種模式與Object祖先

三種單例模式 object 單例有三種模式,懶漢式,餓漢式,和優化後的懶漢式 餓漢式單例模式: 餓漢式就像饑餓的人一樣先把事情都提前準備好,因為它是先在靜態屬性裏先提前構建好對象,然後再用靜態方法將對象返回出去,所以會提前占用資源,但是速度比較快。例如:懶漢式單例模式: 懶漢式就像懶人一樣要等到事

C++模式的模板基

單例模式是很常用的設計模式,如果希望系統中某個類的物件只能有一個或者有一個就夠了,那麼便可以採用單例模式來解決。 下面用C++實現一個單例模板類,那麼其他的類只需繼承它,便可以成為單例類。 本例中使用了 CMutex類,是考慮多執行緒的情況,這個類的定義請參見筆者的另一篇部落格《C++簡

使用模式封裝網路工具(okH)

我是用的是介面傳值,所以第一步是介面的建立 public interface NetWorkModelInterface { //失敗 void failure(Exception e); //成功 void success(String result)

模式之內部靜態

利用內部靜態類實現單例模式public class Singleton { private Singleton(){ } public static Singleton getInstance() { return Nested.instance; }

java實現模式的幾種方式簡單易懂

一、餓漢式單例類 public class Singleton { private Singleton(){ } private static Singleton instance = new Singleton();

java設計模式(一)建立型模式模式(餓漢式懶漢式執行緒安全雙重檢查)

1.介紹     單例模式是一種常用的軟體設計模式,其定義是單例物件的類只能允許一個例項存在。  2.實現思路與步驟   1).將該類的構造方法定義為私有方法,這樣其他處的程式碼就無法通過呼叫該類的構造方法來例項化該類的物件,只有通過該類提供的靜態

JAVA模式的各種寫法分析最優為列舉

作用 單例模式(Singleton):保證一個類僅有一個例項,並提供一個訪問它的全域性訪問點 適用場景 應用中某個例項物件需要頻繁的被訪問。 應用中每次啟動只會存在一個例項。如資料庫系統。 使用方式 懶漢式 public class Singleton { /* 持有私有靜

Java模式(餓漢式懶漢式)我更願稱作(傳統銷售式飢餓營銷式)

單例模式是一個很經典的設計模式,在java中無處不在。比如spring中的bean注入,工具類的編寫等。但是在剛接觸單例模式時候,我總對這個飽漢式和餓漢式的稱呼理解不好。下面來講一講我自己的理解。1)餓漢模式(傳統銷售式) class A{ private A(){} privat

模式的設計與實現及效能測試

單例模式在實際應用中使用非常廣泛,比如日誌寫入,單例模式可以避免錯誤,資料庫連線可以避免鎖死,用例執行可以避免重複呼叫。 先是列舉實現法: public enum Singleton01 { INSTANCE; public void operator() { S

模式(泛型

 在專案開發過程中,經常會涉及到多個採用單例模式的類,對每個類都要進行單例的處理,甚是不爽。 下面使用泛型類解決了這個問題,只要簡單繼承就可以了,程式碼如下: namespace LogHelper { using System; /// <sum

模式封裝的logging庫的實現(Python)

import logging import sys def __singletion(cls): """ 單例模式的裝飾器函式 :param cls: 實體類 :return: 返回實體類物件 """ instances =

【設計模式模式之執行緒

好記性,不如爛筆頭。對於單例模式的理解和應用還是需要多多實踐,這次有感而發,寫份基於執行緒執行的單例模式。 單例模式該怎樣去實現:建構函式宣告為private或protect防止被外部函式例項化,內部

載入一個其內部類是否同時被載入?靜態內部類模式

載入一個類時,其內部類是否同時被載入?下面我們做一個實驗來看一下。  Java程式碼   public class Outer {       static {           System.out.println("load outer class..."); 

載入一個其內部類是否同時被載入?引申出模式的另一種實現方式...

載入一個類時,其內部類是否同時被載入?下面我們做一個實驗來看一下。public class Outer { static { System.out.println("load outer class..."); } //靜態內部類 sta

載入一個其內部類是否同時被載入?引申出模式的另一種實現方式

 載入一個類時,其內部類是否同時被載入?下面我們做一個實驗來看一下。  Java程式碼   1.    public class Outer {   2.        static {   3.            System.out.println("load o

__call__方法和模式

rom pan AR erro metaclass self acl clas HA 在python中一切皆對象的概念。 舉一個例子: class Chinese: country=“china” def __init__(self, name,age,s

python模式控制成只初始化一次常規型的python模式在新式和經典的區別。

spa alt let __main__ python2 urn 時間 div 分享 單例模式的寫法非常多,但常規型的單例模式就是這樣寫的,各種代碼可能略有差異,但核心就是要搞清楚類屬性 實例屬性,就很容易寫出來,原理完全一模一樣。 如下: 源碼: class

日期時間日期時間模式裝箱與拆箱數字隨機數BigDecimal總結

方便 下標 時分秒 etime 相等 創建 rep style with 1.日期類,時間類,日期時間類 初步日期使用方法及格式轉換方法(舊方法): 格式://Mon Jul 30 11:26:05 CST 2018 年月日時分秒 CST代表北