在這裏的單例就是隻有一個實例(這裏的實例就像在面向對象的時候,建立了一個對象也能夠說建立了一個實例),只用一個實例進行程序設計,首先咱們能夠了解一下何時不適合使用單例模式,好比咱們須要使用類同時建立多個對象的時候,且每一個對象中封裝了不一樣的數據的時候,就不能使用單例模式,就像下面的例子python
class Person: def __init__(self, name, age): self.name = name self.age = age zhangsan = Person('張三', 21) lisi = Person('李四', 38) wangwu = Person('王五', 37)
那麼何時適合使用單例模式,若是每一個對象中封裝了相同的數據,可是須要建立多個對象的時候,並且這兩個實例全部的功能是同樣的,因此咱們就可使用一個實例完成,在這裏咱們就可使用單例模式,以下數據庫
class Person: def __init__(self): self.name = '123' self.age = '20' def f1(self): pass def f2(self): pass zhangsan = Person() zhangsan.f1() lisi = Person() lisi.f1()
爲何要使用單例模式,就是爲了在封裝數據相同的狀況下,並且每一個實例可執行的方法相同的時候,沒必要建立多個對象,只須要使用一個實例,來完成多個相同實例所完成的功能,經過這種方式減小內存的使用。多線程
優勢dom
系統內存中該類只存在一個對象,節省了系統資源,對於一些須要頻繁建立銷燬的對象,使用單例模式能夠提升系統性能。工具
因爲單例模式在內存中只有一個實例,減小了內存開銷。性能
單例模式能夠避免對資源的多重佔用,例如一個寫文件時,因爲只有一個實例存在內存中,避免對同一個資源文件的同時寫操做。優化
單例模式能夠在系統設置全局的訪問點,優化和共享資源訪問。spa
其中使用到單例模式時,考慮較多的就是多線程的狀況下如何防止被多線程同時建立等問題。線程
當這個類的對象在多個地方建立的時候,使得內部的方法屢次調用,可是但願只要一個對象操做這個方法,或者不但願多個地方同時調用這個方法,須要保持這個方法的單一性質,就用單例模式。設計
缺點
使用單例模式,擴展很困難,若要擴展,除了修改代碼基本上沒有第二種途徑能夠實現。
接下來咱們就模擬一個數據庫鏈接池來實現單例模式
首先咱們介紹一下數據庫鏈接池
咱們經過程序進行數據庫的操做的時候,每次都須要鏈接數據庫,可是鏈接數據庫須要消耗較多的時間,因此咱們能夠在咱們主機的內存裏維護一個數據庫鏈接池,在這個鏈接池中有若干個已經鏈接數據庫的鏈接,咱們想要鏈接數據庫的時候直接到鏈接池中取出一個鏈接便可,省去了鏈接的時間。
非單例模式
import random class SqlConnectionPool: __instance = None def __init__(self): self.ip = '127.0.0.1' self.port = 3306 self.pwd = '123456' self.username = 'jhong' # 去鏈接 self.conn_list = [1, 2, 3, 4, 5, 6, 7, 8] def get_connection(self): # 獲取鏈接 r = random.randrange(1, 9) return r # 咱們建立多個對象內存地址是同樣的,說明拿到的是同一個對象 obj = SqlConnectionPool() print(obj) obj1 = SqlConnectionPool() print(obj1) obj2 = SqlConnectionPool() print(obj2)
輸出結果:
能夠發現非單例模式每次內存輸出的結果都不一樣,下面是單例模式:
import random class SqlConnectionPool: __instance = None def __init__(self): self.ip = '127.0.0.1' self.port = 3306 self.pwd = '123456' self.username = 'jhong' # 去鏈接 self.conn_list = [1, 2, 3, 4, 5, 6, 7, 8] @staticmethod # 靜態方法是由類調用的 def get_instance(): if SqlConnectionPool.__instance: return SqlConnectionPool.__instance else: # 建立一個對象,並將對象賦值給靜態字段__instance SqlConnectionPool.__instance = SqlConnectionPool() return SqlConnectionPool.__instance # 單例模式關鍵代碼解析 # 當第一次調用這個靜態方法的時候,判斷__instance的值是None因此執行else,而後在else中建立一個對象賦值給靜態字段__instance,而後返回這個靜態字段 # 第二次調用這個靜態方法的時候,判斷__instance的值爲真,因此直接返回這個靜態字段,而這個靜態字段中包含的是第一次建立的對象,因此在之後調用這個方法就只會調用第一次建立的對象,這就是單例模式 def get_connection(self): # 獲取鏈接 r = random.randrange(1, 9) return r # 咱們建立多個對象內存地址是同樣的,說明拿到的是同一個對象 obj = SqlConnectionPool.get_instance() print(obj) obj1 = SqlConnectionPool.get_instance() print(obj1) obj2 = SqlConnectionPool.get_instance() print(obj2)
輸出結果:
以上是基於類,使用靜態字段和靜態方法實現的一個單例模式。