1. 程式人生 > >Python設計模式——單例模式

Python設計模式——單例模式

ack 查看 繼承 一起 實現 不同的 ont 大神 使用方法

一、單例模式理論

單例模式:
保證某一個類只有一個實例,而且在全局只有一個訪問點
優點:
1、由於單例模式要求在全局內只有一個實例,因而可以節省比較多的內存空間
2、全局只有一個接入點,可以更好地進行數據同步控制,避免多重占用
3、單例可長駐內存,減少系統開銷

缺點:
1、單例模式的擴展是比較困難的
2、賦予了單例模式太多的職責,某種程度上違反了單一職責原則(六大設計原則之一)
3、單例模式是並發協作軟件模塊中需要最先完成的,因而其不利於測試
4、單例模式在某種情況下會導致資源瓶頸

應用場景:
1、生成全局唯一的變量,比如序列號
2、訪問全局復用的唯一資源,如磁盤,總線等
3、單個對象占用的資源太多,如數據庫等
4、系統全局統一管理,如windows下的任務管理器

二、對__new__的分析

# class Demo:
#     def __init__(self, name):
#         self.name = name
#
#     def show_name(self):
#         print("Name is: {}".format(self.name))
#
# if __name__ == '__main__':
#
#     d = Demo("toby")
#     d.show_name()

'''
引用大神的描述:
    這樣便是__init__最普通的用法了。但__init__其實不是實例化一個類的時候第一個被調用的方法。
    當使用Demo("toby")這樣的表達式來實例化一個類時,最先被調用的方法其實是 __new__ 方法。
    __new__ 方法是什麽?
    __new__方法接受的參數雖然也是和__init__一樣,但__init__是在類實例創建之後調用,而__new__方法正是創建這個類實例的方法。
'''

class Demo:
    def __new__(cls, name):
        print("Call __new__")
        class_instance = super(Demo, cls).__new__(cls)
        print("new創建了類實例:", class_instance) #打印一下
        return class_instance #返回Demon類的一個實例給__init__,然後利用這個實例來調用類的__init__方法

    def __init__(self, name): #那__init__用什麽來接收__new__返回來的類實例呢?答案就是self
        print("init接收到new返回回來的類實例:", self) #打印一下這個self,也就是看一下由__new__產生的實例
        print("Call __init__")
        self.name = name

    def show_name(self):
        print("Name is: {}".format(self.name))
#
# if __name__ == '__main__':
#     d = Demo("toby")
#     d.show_name()

'''
引用大神的總結:
    所以,__init__ 和 __new__ 最主要的區別在於:
    1、__init__ 通常用於初始化一個新實例,控制這個初始化的過程,比如添加一些屬性, 
    做一些額外的操作,發生在類實例被創建完以後。它是實例級別的方法。
    2、__new__ 通常用於控制生成一個新實例的過程。它是類級別的方法。
    但是說了這麽多,__new__最通常的用法是什麽呢,我們什麽時候需要__new__?,單例模式就是一個很好的例子
'''

三、單例模式(案例1)

#coding:utf-8
import threading
import time

#這裏使用方法__new__來實現單例模式
class Singleton(object): #抽象單例
    def __new__(cls, *args, **kwargs):
        if not hasattr(cls, "_instance"):
            orig = super(Singleton, cls)
            cls._instance = orig.__new__(cls, *args, **kwargs)
        return cls._instance

#總線
class Bus(Singleton):
    lock = threading.RLock()
    def sendData(self, data):
        self.lock.acquire()
        time.sleep(3)
        print("Sending Signal Data...", data)
        self.lock.release()

#線程對象,為更加說明單例的含義,這裏講Bus對象實例化在了run裏
class VisitEntity(threading.Thread):
    my_bus = ""
    name = ""
    def getName(self):
        return self.name
    def setName(self, name):
        self.name = name
    def run(self):
        self.my_bus = Bus()
        self.my_bus.sendData(self.name)
if __name__ == '__main__':
    for i in range(3):
        print("Entity {} begin to run...".format(i))
        v = VisitEntity()
        v.setName("Toby"+str(i))
        v.start()

四、單例模式(案例2)

#使用__new__類方法來保證只有一個實例被創建出來
class OneOnly(object):
    _singleton = None
    def __new__(cls, *args, **kwargs):
        if not cls._singleton: #判斷是否創建有實例,如果沒有則調用super()函數來創建它
            cls._singleton = super(OneOnly, cls).__new__(cls) #構造方法__new__被調用時,會構造該類的一個新實例
        return cls._singleton

#定義一個普通的類,僅有初始化方法__init__
class Test:
    def __init__(self, name):
        self.name = name

#定義一個Demo類,並繼承實現單例模式的OneOnly類
class Demo(OneOnly):
    def __init__(self, name):
        self.name = name

    def chage_name(self, new_name):
        self.name = new_name

    def show_name(self):
        print("Name is: {}".format(self.name))

if __name__ == '__main__':

    #當通過OneOnly類中的構造方法構造實例時,總是會的得到完全相同的實例,內存地址也相同
    # o1 = OneOnly()
    # o2 = OneOnly()
    # print(o1)
    # print(o2)

    #通過Test類創建出來的兩個實例t1和t2,是兩個不同的實例,內存地址也是不同的
    # t1 = Test("toby")
    # t2 = Test("ttr")
    # print(t1)
    # print(t2)

    #Demo類繼承了實現了單例模式的OneOnly類,因此,通過Demo類實例化出來的對象都是同一個對象
    d1 = Demo("toby")
    d2 = Demo("ttr")
    d3 = Demo("laowang")
    # 通過打印可知,他們的內存地址都是一樣的
    # print(d1)
    # print(d2)

    #發現打印出來的name都是"laowang",似乎最後創建的一個實例把前兩個的給覆蓋了
    d1.show_name()
    d2.show_name()
    d3.show_name()

    #通過實例d1修改名字後,再通過實例d3和d2來查看,果然也一起改變了。由此證明他們確實是同一個實例
    d1.chage_name("juck")
    d3.show_name()
    d2.show_name()


Python設計模式——單例模式