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

1、單例模式存在的意義

  在這裏的單例就是隻有一個實例(這裏的實例就像在面向對象的時候,建立了一個對象也能夠說建立了一個實例),只用一個實例進行程序設計,首先咱們能夠了解一下何時不適合使用單例模式,好比咱們須要使用類同時建立多個對象的時候,且每一個對象中封裝了不一樣的數據的時候,就不能使用單例模式,就像下面的例子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()

  爲何要使用單例模式,就是爲了在封裝數據相同的狀況下,並且每一個實例可執行的方法相同的時候,沒必要建立多個對象,只須要使用一個實例,來完成多個相同實例所完成的功能,經過這種方式減小內存的使用。多線程

2、單例模式應用的場景  

  • 須要頻繁的進行建立和銷燬的對象;
  • 建立對象時耗時過多或耗費資源過多,但又常常用到的對象;
  • 工具類對象;
  • 頻繁訪問數據庫或文件的對象。

3、單例模式的優勢以及缺點

優勢dom

系統內存中該類只存在一個對象,節省了系統資源,對於一些須要頻繁建立銷燬的對象,使用單例模式能夠提升系統性能。工具

因爲單例模式在內存中只有一個實例,減小了內存開銷。性能

單例模式能夠避免對資源的多重佔用,例如一個寫文件時,因爲只有一個實例存在內存中,避免對同一個資源文件的同時寫操做。優化

單例模式能夠在系統設置全局的訪問點,優化和共享資源訪問。spa

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

當這個類的對象在多個地方建立的時候,使得內部的方法屢次調用,可是但願只要一個對象操做這個方法,或者不但願多個地方同時調用這個方法,須要保持這個方法的單一性質,就用單例模式。設計

缺點

使用單例模式,擴展很困難,若要擴展,除了修改代碼基本上沒有第二種途徑能夠實現。

4、單例模式代碼編寫

接下來咱們就模擬一個數據庫鏈接池來實現單例模式

首先咱們介紹一下數據庫鏈接池

咱們經過程序進行數據庫的操做的時候,每次都須要鏈接數據庫,可是鏈接數據庫須要消耗較多的時間,因此咱們能夠在咱們主機的內存裏維護一個數據庫鏈接池,在這個鏈接池中有若干個已經鏈接數據庫的鏈接,咱們想要鏈接數據庫的時候直接到鏈接池中取出一個鏈接便可,省去了鏈接的時間。

非單例模式

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)  

輸出結果:

以上是基於類,使用靜態字段和靜態方法實現的一個單例模式。

相關文章
相關標籤/搜索