天天看點

Python學習:19.Python設計模式-單例模式

一、單例模式存在的意義

  在這裡的單例就是隻有一個執行個體(這裡的執行個體就像在面向對象的時候,建立了一個對象也可以說建立了一個執行個體),隻用一個執行個體進行程式設計,首先我們可以了解一下什麼時候不适合使用單例模式,比如我們需要使用類同時建立多個對象的時候,且每個對象中封裝了不同的資料的時候,就不能使用單例模式,就像下面的例子

class Person:
    def __init__(self,name,age):
        self.name = name
        self.age = age
        
mingming = Person('明明',19)
mingyue = Person('明月',30)
mingri = Person('明日',20)      

  那麼什麼時候适合使用單例模式,如果每個對象中封裝了相同的資料,但是需要建立多個對象的時候,而且這兩個執行個體所有的功能是一樣的,是以我們就可以使用一個執行個體完成,在這裡我們就可以使用單例模式,如下

class Person:
    def __init__(self):
        self.name = '123123'
        self.age = '20'

    def f1(self):
        pass

    def f2(self):
        pass

mingming = Person()
mingming.f1()

mingyue = Person()
mingyue.f1()      

  為什麼要使用單例模式,就是為了在封裝資料相同的情況下,而且每個執行個體可執行的方法相同的時候,不必建立多個對象,隻需要使用一個執行個體,來完成多個相同執行個體所完成的功能,通過這種方式減少記憶體的使用。

二、單例模式應用的場景

  • 需要頻繁的進行建立和銷毀的對象;
  • 建立對象時耗時過多或耗費資源過多,但又經常用到的對象;
  • 工具類對象;
  • 頻繁通路資料庫或檔案的對象。

三、單例模式的優點以及缺點

優點

系統記憶體中該類隻存在一個對象,節省了系統資源,對于一些需要頻繁建立銷毀的對象,使用單例模式可以提高系統性能。

由于單例模式在記憶體中隻有一個執行個體,減少了記憶體開銷。 

單例模式可以避免對資源的多重占用,例如一個寫檔案時,由于隻有一個執行個體存在記憶體中,避免對同一個資源檔案的同時寫操作。 

單例模式可以再系統設定全局的通路點,優化和共享資源通路。 

其中使用到單例模式時,考慮較多的就是多線程的情況下如何防止被多線程同時建立等問題。

當這個類的對象在多個地方建立的時候,使得内部的方法多次調用,但是希望隻要一個對象操作這個方法,或者不希望多個地方同時調用這個方法,需要保持這個方法的單一性質,就用單利模式

缺點

使用單例模式,擴充很困難,若要擴充,除了修改代碼基本上沒有第二種途徑可以實作。

四、單例模式代碼編寫

接下來我們就模拟一個資料庫連接配接池來實作單例模式

首先我們介紹一下資料庫連接配接池

我們通過程式進行資料庫的操作的時候,每次都需要連接配接資料庫,但是連接配接資料庫需要消耗較多的時間,是以我們可以在我們主機的記憶體裡維護一個資料庫連接配接池,在這個連接配接池中有若幹個已經連接配接資料庫的連接配接,我們想要連接配接資料庫的時候直接到連接配接池中取出一個連接配接即可,省去了連接配接的時間。

非單例模式

import random

class SqlConnectionPool:

    __instance = None

    def __init__(self):
        self.ip = "127.0.0.1"
        self.port = 3306
        self.pwd = '123456'
        self.username = 'alexsel'
        #去連接配接
        self.conn_list = [1,2,3,4,5,6,7,8,9,10]

    def get_connection(self):
        #擷取連接配接
        r = random.randrange(1,11)
        return r


#我們建立多個對象記憶體位址是一樣的,說明拿到的是同一個對象
obj = SqlConnectionPool()
print(obj)
obj1 = SqlConnectionPool()
print(obj1)
obj2 = SqlConnectionPool()
print(obj2)

輸出結果:
<__main__.SqlConnectionPool instance at 0x0000000002630788>
<__main__.SqlConnectionPool instance at 0x0000000002630888>
<__main__.SqlConnectionPool instance at 0x00000000026308C8>      

非單例模式每次記憶體輸出的結果都不同,下面是單例模式。

import random

class SqlConnectionPool:

    __instance = None

    def __init__(self):
        self.ip = "127.0.0.1"
        self.port = 3306
        self.pwd = '123456'
        self.username = 'alexsel'
        #去連接配接
        self.conn_list = [1,2,3,4,5,6,7,8,9,10]

    @staticmethod   #靜态方法是由類調用的
    def get_instance():
        if SqlConnectionPool.__instance:
            return SqlConnectionPool.__instance
        else:
            #建立一個對象,并将對象指派給靜态字段__instance
            SqlConnectionPool.__instance = SqlConnectionPool()
            return SqlConnectionPool.__instance

    #單例模式關鍵代碼解析
    #當第一次調用這個靜态方法的時候,判斷__instacne的值是None是以執行else,然後在else中建立一個對象賦給靜态字段__instance,然後傳回這個靜态字段
    #第二次調用這個今靜态方法的時候,判斷__instance的值為真,是以直接傳回這個靜态字段,而這個靜态字段中包含的是第一次建立的對象,是以在以後調用這個方法
    #就隻會調用第一次建立的對象,這就是單例模式

    def get_connection(self):
        #擷取連接配接
        r = random.randrange(1,11)
        return r


#我們建立多個對象記憶體位址是一樣的,說明拿到的是同一個對象
obj = SqlConnectionPool.get_instance()
print(obj)
obj1 = SqlConnectionPool.get_instance()
print(obj1)
obj2 = SqlConnectionPool.get_instance()
print(obj2)


輸出結果:
<__main__.SqlConnectionPool instance at 0x000000000260C808>
<__main__.SqlConnectionPool instance at 0x000000000260C808>
<__main__.SqlConnectionPool instance at 0x000000000260C808>      

 以上是基于類,使用靜态字段和靜态方法實作的一個單例模式。

轉載于:https://www.cnblogs.com/liudi2017/p/9393614.html