基本設計模式:單例模式和工廠模式代碼實現


單例模式

      單例模式保證一個類僅有一個實例,並提供一個訪問它的全局訪問點。通常我們可以讓一個全局變量使得一個對象被訪問,但它不能阻止你實例化多個對象。一個最好的辦法是,讓類自身負責保存它的唯一實例。這個類可以保證沒有其他實例可以被創建,並且它可以提供一個訪問該實例的方法。

      也就是說,很多時候我們需要全局的對象,如一個工程中,數據庫訪問對象只有一個,這時,可以考慮使用單例模式。單例模式比全局對象好還包括:單例類可以繼承,如下例中的C++代碼。

     單例模式的關鍵點在於:構造函數私有,靜態的GetInstance

     另外,在C++中必須注意內存的釋放。C++、Java、C#中還要注意多線程時的同步問題,另外在多線程可以以合適的方式保證共享變量僅初始化一次

 

以下列出懶漢式的單例模式

C++實現:

class Singleton  
{  
  public:  
    static Singleton * GetInstance()  
    {  
        if(NULL == m_pInstance)  
            m_pInstance = new Singleton();  
        return m_pInstance;  
    }  
    static void Release()                    //必須,否則會導致內存泄露   
    {  
        if(NULL != m_pInstance)  
        {  
            delete m_pInstance;  
            m_pInstance = NULL;  
        }  
    }  
      
   protected:  
     Singleton()  
     {  
         cout<<"C++ Singleton"<<endl;  
     };  
     static Singleton * m_pInstance;  
}; 

Singleton* Singleton::m_pInstance = NULL;  
  
class SingleDraw:public Singleton  
{  
public:  
    static SingleDraw* GetInstance()  
    {  
        if(NULL == m_pInstance)  
            m_pInstance = new SingleDraw();  
        return (SingleDraw*)m_pInstance;  
    }  
protected:  
    SingleDraw()  
    {  
        cout<<"C++ SingleDraw"<<endl;  
    }  
};  
  
int main()  
{  
    SingleDraw* s1 = SingleDraw::GetInstance();  
    SingleDraw* s2 = SingleDraw::GetInstance();  
    s2->Release();  
    return 0;  
}  

 

Java實現(這里僅給出類實現部分):

public class Singleton{

     private static Singleton instance=NULL;
     
     private Singleton(){
          System.out.println("Java Singleton");
     }

     public static Singleton getInstance(){
          if(instance == NULL)
               instance = new Singleton();
          return instance;
     }
}


還有另一種形式: 餓漢單例,也就是,類被加載的時候就已經創建好了單例,相比懶漢式只是加載new的地方發生了改變,這里代碼重略

 

餓漢式和懶漢式的比較:

1 餓漢式單例,由於類被加載的時候就將自己實例化,所以,從資源利用的角度來說,餓漢式單例比懶漢式單例效率更差

2 懶漢式單例在實例化的時候,必須處理好多個線程同時引用造成的訪問限制問題.也就是,很有可能有兩個線程同時去調用了這個獲取單例的方法,造成了單例被創建了多次懶漢式單例模式線程安全問題:假如現在有兩個線程A和線程B,線程A執行到 this.singletonPattern = new SingletonPattern(),正在申請內存分配,可能需要0.001微秒,就在這0.001微秒之內,線程B執行到if(this.singletonPattern == null),你說這個時候這個判斷條件是true還是false?是true,那然后呢?線程B也往下走,於是乎就在內存中就有兩個SingletonPattern的實例了。所以,在編寫懶漢式單例模式時,應注意線程安全問題(由全局變量及靜態變量引起的),這里可以用互斥同步的方式去解決。(面試可考的地方)

3 餓漢式單例類可以在Java 語言內實現, 但不易在C++ 內實現因為靜態初始化在C++ 里沒有固定的順序,因而靜態的m_instance 變量的初始化與類的加載順序沒有保證,可能會出問題。這就是為什么GoF 在提出單例類的概念時,舉的例子是懶漢式的。他們的書影響之大,以致Java 語言中單例類的例子也大多是懶漢式的

 

工廠模式

首先需要說一下工廠模式。工廠模式根據抽象程度的不同分為三種:簡單工廠模式(也叫靜態工廠模式)、這里所講述的工廠方法模式、以及抽象工廠模式。工廠模式是編程中經常用到的一種模式。它的主要優點有:

  • 可以使代碼結構清晰,有效地封裝變化。在編程中,產品類的實例化有時候是比較復雜和多變的,通過工廠模式,將產品的實例化封裝起來,使得調用者根本無需關心產品的實例化過程,只需依賴工廠即可得到自己想要的產品
  • 對調用者屏蔽具體的產品類。如果使用工廠模式,調用者只關心產品的接口就可以了,至於具體的實現,調用者根本無需關心。即使變更了具體的實現,對調用者來說沒有任何影響。
  • 降低耦合度。產品類的實例化通常來說是很復雜的,它需要依賴很多的類,而這些類對於調用者來說根本無需知道,如果使用了工廠方法,我們需要做的僅僅是實例化好產品類,然后交給調用者使用。對調用者來說,產品所依賴的類都是透明的。

C++實現:

#include <iostream>

using namespace std;

class IProduct
{
public:
    virtual void productMethod() = 0;
};


class Product:public IProduct
{
public:
    void productMethod() 
    {  
        cout<<"C++ productMethod call"<<endl;  
    }  
};


class IFactory { public: virtual IProduct* CreateProduct() = 0; };
class ConcreateFactory:public IFactory { public: IProduct* CreateProduct() { IProduct* p = new Product(); return p; } }; int main() { IFactory* pFactory = new ConcreateFactory(); IProduct* p = pFactory->CreateProduct(); p->productMethod(); delete p; return 1; }


Java實現

interface IProduct {  
    public void productMethod();  
}  
  

class Product implements IProduct { public void productMethod() { System.out.println("Java productMethod call"); } }
interface IFactory { public IProduct createProduct(); }
class Factory implements IFactory { public IProduct createProduct() { return new Product(); } }
public class Client { public static void main(String[] args) { IFactory factory = new Factory(); IProduct prodect = factory.createProduct(); prodect.productMethod(); } }

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM