何為單例?
簡單介紹一下下:單例是個什么鬼東西!!!!
單例模式含義】
單例模式是一種常用的軟件設計模式。在它的核心結構中只包含一個被稱為單例類的特殊類。通過單例模式可以保證系統中一個類只有一個實例而且該實例易於外界訪問,從而方便對實例個數的控制並節約系統資源。如果希望在系統中某個類的對象只能存在一個,單例模式是最好的解決方案。
【采用單例模式動機、原因】
對於系統中的某些類來說,只有一個實例很重要,例如,一個系統中可以存在多個打印任務,但是只能有一個正在工作的任務;一個系統只能有一個窗口管理器或文件系統;一個系統只能有一個計時工具或ID(序號)生成器。如在Windows中就只能打開一個任務管理器。如果不使用機制對窗口對象進行唯一化,將彈出多個窗口,如果這些窗口顯示的內容完全一致,則是重復對象,浪費內存資源;如果這些窗口顯示的內容不一致,則意味着在某一瞬間系統有多個狀態,與實際不符,也會給用戶帶來誤解,不知道哪一個才是真實的狀態。因此有時確保系統中某個對象的唯一性即一個類只能有一個實例非常重要。
如何保證一個類只有一個實例並且這個實例易於被訪問呢?定義一個全局變量可以確保對象隨時都可以被訪問,但不能防止我們實例化多個對象。一個更好的解決辦法是讓類自身負責保存它的唯一實例。這個類可以保證沒有其他實例被創建,並且它可以提供一個訪問該實例的方法。這就是單例模式的模式動機。
【單例模式優缺點】
【優點】
一、實例控制
單例模式會阻止其他對象實例化其自己的單例對象的副本,從而確保所有對象都訪問唯一實例。
二、靈活性
因為類控制了實例化過程,所以類可以靈活更改實例化過程。
【缺點】
一、開銷
雖然數量很少,但如果每次對象請求引用時都要檢查是否存在類的實例,將仍然需要一些開銷。可以通過使用靜態初始化解決此問題。
二、可能的開發混淆
使用單例對象(尤其在類庫中定義的對象)時,開發人員必須記住自己不能使用new關鍵字實例化對象。因為可能無法訪問庫源代碼,因此應用程序開發人員可能會意外發現自己無法直接實例化此類。
三、對象生存期
不能解決刪除單個對象的問題。在提供內存管理的語言中(例如基於.NET Framework的語言),只有單例類能夠導致實例被取消分配,因為它包含對該實例的私有引用。在某些語言中(如 C++),其他類可以刪除對象實例,但這樣會導致單例類中出現懸浮引用
單例模式的簡單理解
1 單例模式 只允許創建一個對象,因此節省內存,加快對象訪問速度,因此對象需要被公用的場合適合使用,如多個模塊使用同一個數據源連接對象等等
2 單例的缺點 就是不適用於變化的對象,如果同一類型的對象總是要在不同的用例場景發生變化,單例就會引起數據的錯誤,不能保存彼此的狀態。
用單例模式,就是在適用其優點的狀態下使用
不要天真的以為上面是我寫的! 其實我是抄來的概念!哈哈哈哈....
既然了解了單例模式,下面說說如何使用單例模式
在python中,我們可以用多種方法來實現單例模式:
- 使用模塊
- 使用__new__
- 使用裝飾器
- 使用元類(metaclass)
使用模塊
其實,python的模塊就是天然的單例模式,因為模塊在第一次導入時,會生成.pyc文件,當第二次導入時,就會直接加載.pyc文件,而不會再次執行模塊代碼。因此我們只需把相關的函數和數據定義在一個模塊中,就可以獲得一個單例對象了。
# mysingle.py class MySingle:
def foo(self):
pass
sinleton = MySingle()
將上面的代碼保存在文件mysingle.py中,然后這樣使用:
from mysingle import sinleton
singleton.foo()
使用__new__
為了使類只能出現一個實例,我們可以使用__new__來控制實例的創建過程,代碼如下:
使用裝飾器:
我們知道,裝飾器可以動態的修改一個類或函數的功能。這里,我們也可以使用裝飾器來裝飾某個類,使其只能生成一個實例:
def singleton(cls): instances = {} def getinstance(*args,**kwargs): if cls not in instances: instances[cls] = cls(*args,**kwargs) return instances[cls] return getinstance @singleton class MyClass: a = 1 c1 = MyClass() c2 = MyClass() print(c1 == c2) # True
在上面,我們定義了一個裝飾器singleton
,它返回了一個內部函數getinstance
,
該函數會判斷某個類是否在字典instances
中,如果不存在,則會將cls
作為 key,cls(*args, **kw)
作為 value 存到instances
中,
否則,直接返回instances[cls]
。
使用metaclass(元類)
元類可以控制類的創建過程,它主要做三件事:
- 攔截類的創建
- 修改類的定義
- 返回修改后的類
使用元類實現單例模式:
class Singleton2(type): def __init__(self, *args, **kwargs): self.__instance = None super(Singleton2,self).__init__(*args, **kwargs) def __call__(self, *args, **kwargs): if self.__instance is None: self.__instance = super(Singleton2,self).__call__(*args, **kwargs) return self.__instance class Foo(object): __metaclass__ = Singleton2 #在代碼執行到這里的時候,元類中的__new__方法和__init__方法其實已經被執行了,而不是在Foo實例化的時候執行。且僅會執行一次。 foo1 = Foo() foo2 = Foo() print (Foo.__dict__) #_Singleton__instance': <__main__.Foo object at 0x100c52f10> 存在一個私有屬性來保存屬性,而不會污染Foo類(其實還是會污染,只是無法直接通過__instance屬性訪問) print (foo1 is foo2) # True
基於pymysql操作的類(單例模式)
from conf import setting import pymysql class Mysql: __instance = None def __init__(self): self.conn = pymysql.connect(host=setting.host, user=setting.user, password=setting.password, database=setting.database, charset=setting.charset, autocommit=setting.autocommit) self.cursor = self.conn.cursor(cursor=pymysql.cursors.DictCursor) def close_db(self): self.conn.close() def select(self, sql, args=None): self.cursor.execute(sql, args) rs = self.cursor.fetchall() return rs def execute(self, sql, args): try: self.cursor.execute(sql, args) affected = self.cursor.rowcount # self.conn.commit() except BaseException as e: print(e) return affected @classmethod def singleton(cls): if not cls.__instance: cls.__instance = cls() return cls.__instance
博客持續更新中,小伙伴們慎入............
Author : rianley cheng
Author email: rianleycheng@gmail.com
Author QQ: 2855132411