要了解單例設計模式,我們首先要了解什麼是設計模式。
設計模式:通俗的講就是每一個模式都是我們在代碼中不斷要遇到的問題,通過分析,然後分類這些問題,進行代碼的設計和經驗的總結。爲了就是可重用代碼,讓代碼的設計更容易被他人理解,保證了代碼的可靠性。
單例設計模式:目的就是讓類創建的對象,在系統中只有唯一的實例,每一次執行類名()返回的對象,內存地址是相同的,這樣就可以讓軟件更加的有秩序的運行,也節省了內存。
應用對場景:
回收站(在系統的運行中,回收站一直存在僅有的一個實例)
任務管理器(在系統中只能打開一個任務管理器)
Django框架中的配置文件讀取,也是單例模式,因爲配置文件是共享的資源
還有一些軟件也是遵循這種方法音頻類的軟件基本上都是單例模式,在這就不一一列舉了。
下面我們就以回收站做一個簡單的實例:
在使用單例前我們還要理解__new__這個python的內置方法。
當我們創建一個類的時候,我們基本上用的最常用的是__init__初始化的方法,在這個方法中可以定義實例的屬性。
但是在類中創建每個對象時,都要給這個對象分配空間,這個任務就交給了__new__方法
所以當我們要寫單例模式的時候我們首先要對__new__方法進行重構。
下面我們先實現這個__new__方法
class Trash(object):
def __new__(cls, *args, **kwargs):
print("new方法被調用")
def __init__(self):
print('開始收集')
a = Trash()
print(a)
---------------------->
new方法被調用
None
通過上面的代碼我們看出__new__方法中有三個參數,第一個參數就是哪個類調用就傳遞哪個類,現在傳遞的就是Trash類。
後面兩個參數可以看我的這篇博客(https://blog.csdn.net/qq_42992704/article/details/104244084),另外我們可以看出我們返回的結果中沒有初始化的值。這是因爲我們沒有分配空間和返回對象的引用,只是在創建這個對象時,new的方法被自動調用了。
要怎樣分配空間和返回對象引用呢?
在這我們可以調用object基類中的__new__的默認方法,它已經可以爲對象分配空間。
class Trash:
def __new__(cls, *args, **kwargs):
print("new方法被調用")
space = super().__new__(cls)
return space
def __init__(self):
print('開始收集')
a = Trash()
print(a)
---------------------->
new方法被調用
開始收集
<__main__.Trash object at 0x00000271EDFD6BA8>
有上面我們看的出通過繼承父類的new方法,便可以爲a這個實例對象創建空間。
return space 由sapce接收了父類方法返回的結果,然後在返回這個變量,__new__的方法也就重構完成。這樣我們就可以接受到實例中的屬性。
講到這我們也只是介紹了怎樣改造__new__這個方法, 下面便會引出怎樣將許多軟件回收到垃圾桶裏
class Trash:
def __new__(cls, *args, **kwargs):
print("new方法被調用")
space = super().__new__(cls)
return space
def __init__(self):
self.name = name
print('卸載完成')
mooc = Trash()
dingding= Trash()
xuexitong = Trash()
print(mooc,dingding,xuexitong)
---------------------->
new方法被調用
卸載完成
new方法被調用
卸載完成
new方法被調用
卸載完成
<__main__.Trash object at 0x000002B99B946BA8> <__main__.Trash object at 0x000002B99B946B70> <__main__.Trash object at 0x000002B99B946BE0>
通過上面的代碼我們當我們創建三個實例對象的時候,在Trash類中每次都會創建一個新的內存。對於這類都是屬於同一類的對象來說,顯然這樣是我們不希望的。所以我們稍微改進一下,先呈上。
class Trash:
space = None
def __new__(cls, *args, **kwargs):
if cls.space is None:
print("new方法被調用")
cls.space = super().__new__(cls)
return cls.space
def __init__(self):
print('卸載完成')
mooc = Trash()
dingding= Trash()
xuexitong = Trash()
print(mooc,dingding,xuexitong)
--------------------------->
new方法被調用
卸載完成
卸載完成
卸載完成
<__main__.Trash object at 0x0000020C7A636BA8> <__main__.Trash object at 0x0000020C7A636BA8> <__main__.Trash object at 0x0000020C7A636BA8>
在改進中,我們分析了我們所遇到的核心問題:多次調用的方法本質上還是一個對象,也就是唯一的實例。所以我們要對是否分配空間做一次判斷,如果已經創建空間,那麼在下次來的時候直接返回對象的引用。
-------------->引出了我們對單例的理解:在類創建對象的時候,不管你調用多少次類的方法,得到的結果永遠都是內存中唯一的實例。這就是我們單例所想要達到結果。
上面我們一直都是在改造__new__的方法實現單例,下面我們也應該對初始化的方法下手改造了。
class Trash:
space = None
flag = False
def __new__(cls, *args, **kwargs):
if cls.space is None:
print("new方法被調用")
cls.space = super().__new__(cls)
return cls.space
def __init__(self):
if Trash.flag:
return
print('卸載完成')
Trash.flag = True
mooc = Trash()
dingding= Trash()
xuexitong = Trash()
print(mooc,dingding,xuexitong)
------------------------------>
new方法被調用
卸載完成
<__main__.Trash object at 0x0000027B34966BE0> <__main__.Trash object at 0x0000027B34966BE0> <__main__.Trash object at 0x0000027B34966BE0>
我們可以定義一個類屬性,當我們在創建完對象的引入後,進行判斷讓初始化的方法也只進行調用一次。使用單例方法,可以大大節省了程序運行的時間,減少內存,更加明確類的分工。
see you !!!