全國(guó)咨詢(xún)/投訴熱線(xiàn):400-618-4000

首頁(yè)技術(shù)文章正文

元類(lèi)實(shí)現(xiàn)單例模式

更新時(shí)間:2018-07-13 來(lái)源:黑馬程序員JavaEE培訓(xùn)學(xué)院 瀏覽量:

Python中的類(lèi)也是對(duì)象。元類(lèi)就是用來(lái)創(chuàng)建這些類(lèi)(對(duì)象)的,元類(lèi)就是類(lèi)的類(lèi),你可以這樣理解為:
MyClass = MetaClass()    #元類(lèi)創(chuàng)建
MyObject = MyClass()     #類(lèi)創(chuàng)建實(shí)例

實(shí)際上MyClass就是通過(guò)type()來(lái)創(chuàng)創(chuàng)建出MyClass類(lèi),它是type()類(lèi)的一個(gè)實(shí)例;同時(shí)MyClass本身也是類(lèi),也可以創(chuàng)建出自己的實(shí)例,這里就是MyObject
函數(shù)type實(shí)際上是一個(gè)元類(lèi)。type就是Python在背后用來(lái)創(chuàng)建所有類(lèi)的元類(lèi)?,F(xiàn)在你想知道那為什么type會(huì)全部采用小寫(xiě)形式而不是Type呢?好吧,我猜這是為了和str保持一致性,str是用來(lái)創(chuàng)建字符串對(duì)象的類(lèi),而int是用來(lái)創(chuàng)建整數(shù)對(duì)象的類(lèi)。type就是創(chuàng)建類(lèi)對(duì)象的類(lèi)。你可以通過(guò)檢查_(kāi)_class__屬性來(lái)看到這一點(diǎn)。Python中所有的東西,注意,我是指所有的東西——都是對(duì)象。這包括整數(shù)、字符串、函數(shù)以及類(lèi)。它們?nèi)慷际菍?duì)象,而且它們都是從一個(gè)類(lèi)創(chuàng)建而來(lái)。
那什么是單例呢?為什么我們要用單例設(shè)計(jì)模式?
我們首先來(lái)看看單例模式的使用場(chǎng)景,然后再來(lái)分析為什么需要單例模式。
        ?        Python的logger就是一個(gè)單例模式,用以日志記錄
        ?        Windows的資源管理器是一個(gè)單例模式
        ?        線(xiàn)程池,數(shù)據(jù)庫(kù)連接池等資源池一般也用單例模式
        ?        網(wǎng)站計(jì)數(shù)器
從這些使用場(chǎng)景我們可以總結(jié)下什么情況下需要單例模式:
        1.        當(dāng)每個(gè)實(shí)例都會(huì)占用資源,而且實(shí)例初始化會(huì)影響性能,這個(gè)時(shí)候就可以考慮使用單例模式,它給我們帶來(lái)的好處是只有一個(gè)實(shí)例占用資源,并且只需初始化一次;
        2.        當(dāng)有同步需要的時(shí)候,可以通過(guò)一個(gè)實(shí)例來(lái)進(jìn)行同步控制,比如對(duì)某個(gè)共享文件(如日志文件)的控制,對(duì)計(jì)數(shù)器的同步控制等,這種情況下由于只有一個(gè)實(shí)例,所以不用擔(dān)心同步問(wèn)題。
那什么是單例呢?為什么我們要用單例設(shè)計(jì)模式?
我們首先來(lái)看看單例模式的使用場(chǎng)景,然后再來(lái)分析為什么需要單例模式。
        ?        Python的logger就是一個(gè)單例模式,用以日志記錄
        ?        Windows的資源管理器是一個(gè)單例模式
        ?        線(xiàn)程池,數(shù)據(jù)庫(kù)連接池等資源池一般也用單例模式
        ?        網(wǎng)站計(jì)數(shù)器
從這些使用場(chǎng)景我們可以總結(jié)下什么情況下需要單例模式:
        1.        當(dāng)每個(gè)實(shí)例都會(huì)占用資源,而且實(shí)例初始化會(huì)影響性能,這個(gè)時(shí)候就可以考慮使用單例模式,它給我們帶來(lái)的好處是只有一個(gè)實(shí)例占用資源,并且只需初始化一次;
        2.        當(dāng)有同步需要的時(shí)候,可以通過(guò)一個(gè)實(shí)例來(lái)進(jìn)行同步控制,比如對(duì)某個(gè)共享文件(如日志文件)的控制,對(duì)計(jì)數(shù)器的同步控制等,這種情況下由于只有一個(gè)實(shí)例,所以不用擔(dān)心同步問(wèn)題。

在python中實(shí)現(xiàn)單例模式有幾種方法:

        1. 使用模塊
        2. 使用裝飾器
        3. 使用類(lèi)
        4. 基于__new__方法實(shí)現(xiàn)(推薦使用,方便)
        5. 基于metaclass元類(lèi)方式實(shí)現(xiàn)
這里說(shuō)說(shuō)基于元類(lèi)來(lái)實(shí)現(xiàn)。代碼如下:

class Singleton(type):
    def __init__(cls, name, bases, dic):
        print('元類(lèi)的__init__方法在被執(zhí)行')
        super(Singleton, cls).__init__(name, bases, dic)
        cls.instance = None

    def __call__(cls, *args, **kwargs):
        if not cls.instance:
            print('創(chuàng)建一個(gè)新對(duì)象')
            cls.instance = super(Singleton, cls).__call__(*args, **kwargs)
        else:
            print('單例,只能創(chuàng)建一個(gè)對(duì)象')

        return cls.instance

class A(metaclass=Singleton):

    # __metaclass__ = Singleton
    pass  # python3 取消了__metaclass__屬性

a = A()
b = A()
print(a is b)
print(A.__dict__)

元類(lèi)的__init__方法在被執(zhí)行
創(chuàng)建一個(gè)新對(duì)象
單例,只能創(chuàng)建一個(gè)對(duì)象

True
{'__module__': '__main__', '__dict__': <attribute '__dict__' of 'A' objects>, '__weakref__': <attribute '__weakref__' of 'A' objects>, '__doc__': None, 'instance': <__main__.A object at 0x1027c5cf8>}

本文版權(quán)歸黑馬程序員JavaEE學(xué)院所有,歡迎轉(zhuǎn)載,轉(zhuǎn)載請(qǐng)注明作者出處。謝謝!

作者:黑馬程序員JavaEE培訓(xùn)學(xué)院

首發(fā):http://java.itheima.com/

分享到:
在線(xiàn)咨詢(xún) 我要報(bào)名
和我們?cè)诰€(xiàn)交談!