首頁技術文章正文

元類實現(xiàn)單例模式

更新時間:2018-07-13 來源:黑馬程序員JavaEE培訓學院 瀏覽量:

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

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

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

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

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

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

        return cls.instance

class A(metaclass=Singleton):

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

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

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

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

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

作者:黑馬程序員JavaEE培訓學院

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

分享到:
在線咨詢 我要報名
和我們在線交談!