天天看點

設計模式之單例模式

一、了解單例模式

  確定類有且隻有一個特定類型的對象,并提供全局通路點,單例模式通常用于下列情形,例如日志記錄或資料庫操作等,避免對同一資源請求的互相沖突。

單例的模式的意圖如下:

  • 確定類有且隻有一個對象被建立。
  • 為對象提供一個通路點,以使程式可以全局通路該對象。
  • 控制共享資源的并行通路。

  實作單例模式的一個簡單方法是,使構造函數私有化,并建立一個靜态方法來完成對象的初始化。這樣,對象将在第一次調用時建立,此後,這個類将傳回同一個對象。然後在python中構造函數是無法私有化的,是以需要使用其他方式進行建立。

二、實作

1、基于__new__方法建立單例

  __new__方法是先于__init__方法執行,主要用于建立對象,在完成單例模式時,主要是:隻允許單例類生成一個執行個體;如果已經有一個執行個體了,重複提供同一個對象。這樣保證每一次執行個體化類隻提供一個對象。

class SingleTon(object):

    def __new__(cls, *args, **kwargs):

        if not hasattr(cls,"instance"):
            cls.instance = super(SingleTon,cls).__new__(cls, *args, **kwargs)
        return cls.instance

s=SingleTon()
print(s)

s1=SingleTon()
print(s1)

###輸出###########
#<__main__.SingleTon object at 0x0000000000656828>
#<__main__.SingleTon object at 0x0000000000656828>      

  上面是通過覆寫__new__的方法建立對象的,對象s就是由__new__方法建立的,但是在建立之前會先檢查cls中是否已經有一個對象(instance就是對象),如果沒有就建立一個執行個體,如果已經存在,就将已經存在的執行個體進行傳回。

  s1對象在使用__new__方法建立時,會通過hasattr屬性檢查是否已經存在對象執行個體,此時已經存在s的執行個體,是以将s的執行個體位址傳回給s1。

2、基于getInstance建立單例

  為了避免對記憶體造成浪費,直到需要執行個體化該類的時候才将其執行個體化,是以用getInstance來擷取該對象。

class SingleTon(object):

    _instance=None

    def __init__(self):
        if not SingleTon._instance:
            print("沒有建立對象")
        else:
            print("已經建立對象",self.getInstance())
    @classmethod
    def getInstance(cls):
        if not cls._instance:
            cls._instance=SingleTon()
        return cls._instance

s=SingleTon() #并沒有建立對象

SingleTon.getInstance()  #建立了對象
s1=SingleTon() #對象已經存在
#####################輸出############
#沒有建立對象
#沒有建立對象
#已經建立對象 <__main__.SingleTon object at 0x0000000000676898>      

  當執行s=SingleTon()執行了__init__方法,然而并沒有建立對象,真正建立對象的是在SingleTon.getInstance(),這樣每次在擷取對象時就通過這個靜态方法擷取,不需要使用__new__方法來創造對象。

3、基于子產品級别的單例模式

  python導入子產品的行為決定了每一個子產品都是單例,因為,python在導入子產品時會檢查子產品是否已經導入,如果沒有導入,它會進行導入并且執行個體化,如果已經導入則會傳回該子產品的對象。

  是以,當子產品被導入的時候,它就會被初始化。然而,當同一個子產品被再次導入的時候,它不會再次初始化,因為單例模式隻能有一個對象,是以,它會傳回同一個對象。

使用方式:

  • 在一個py檔案中寫入類并且執行個體化
class AdminSite(object):

    def __init__(self):
        pass

site=AdminSite()      
  • 在另一個py檔案中導入該類對象
from base_moudle.base import site

print(site) #<base_moudle.base.AdminSite object at 0x0000000000D3AE80>      

4、基于元類建立單例

  在python中 一切皆對象,由class關鍵字建立的類也應該是一個對象,那麼,既然是對象,它也應該是由類來建立的,這個類就叫做元類(type)。當通過一個元類來建立一個類時,比如當使用類A建立一個類時,pytno通過A=type(name,bases,dict)建立它。

  • name:這是類的名稱。
  • base:這是基類。
  • dict:這是屬性變量。

比如使用元類建立一個類:

class MyString(type):#繼承type才是一個元類

    def __call__(self, *args, **kwargs):

        return type.__call__(self,*args, **kwargs)

class String(metaclass=MyString):

    def __init__(self,x):
        self.x=x

s=String("abggd")      

  當需要建立對象時,将調用__call__方法,也就是說對象()觸發__call__方法的執行,當對String類進行執行個體化時,實際是MyString元類的對象進行執行個體化,這會觸發__call__方法的運作,它的傳回值就是執行個體化後的結果的接收值,這意味者元類控制着對象的執行個體化。

  同樣的,也就可以利用以上的思路,進行單例模式的實作,為了控制類的建立和初始化,元類将覆寫__new__以及__init__方法。

class MetaSingleTon(type):

    _instance={}
    def __call__(self, *args, **kwargs): #self指代的是傳過來的類 AdminSite
        if self not in self._instance:
            self._instance[self]=super(MetaSingleTon,self).__call__( *args, **kwargs)
        return self._instance[self]

class AdminSite(metaclass=MetaSingleTon):
    pass

a1=AdminSite() #相當于執行元類中的__call__方法,__call__的傳回值是什麼a1就是什麼
print(a1)
a2=AdminSite()
print(a2)

########輸出###########
#<__main__.AdminSite object at 0x0000000000666CC0>
#<__main__.AdminSite object at 0x0000000000666CC0>      

單例模式可以應用于多種場景,這裡提供應用于資料庫層面的,保證資料庫操作一緻性以及提高記憶體使用率。

設計模式之單例模式
設計模式之單例模式
import pymysql
class MetaSingleTon(type):

    _instance={}
    def __call__(self, *args, **kwargs): #self指代的是傳過來的類 AdminSite
        if self not in self._instance:
            self._instance[self]=super(MetaSingleTon,self).__call__( *args, **kwargs)
        return self._instance[self]

class DataBase(metaclass=MetaSingleTon):

    connection=None
    def connect(self):

        if self.connection is None:
            self.connection=pymysql.connect(host='127.0.0.1', port=3306, user='root', passwd='root', db='test', charset='utf8')
            self.cursor=self.connection.cursor()
        return self.cursor

    def excute(self,sql):
        pass

    def close(self):
        self.connect().close()
        self.connection.close()

db1=DataBase()
db2=DataBase()
print(db1)
print(db2)
#########################輸出################
#<__main__.DataBase object at 0x0000000000DF6A90>
#<__main__.DataBase object at 0x0000000000DF6A90>      

操作資料庫

 5、Monostate單例模式

  它與Singleton單例模式是有不同之處的,Singleton關注的是一個類有且隻有一個對象,而Monostate關注的則是一個類不管有多少個對象,所有的對象隻有一個狀态,是以它也被稱為單态模式。那麼它是如何實作這種模式呢?

class Borg:

    __shared_state={}

    def __init__(self):
        self.x=3
        self.__dict__=self.__shared_state

b1=Borg()
b2=Borg()
b2.x=4

print(b1.__dict__)
print(b2.__dict__)
######輸出###########
#{'x': 4}
#{'x': 4}      

  将__shared_state變量作為一個中間變量,并且指派給python中存儲類所有對象狀态的__dict__變量,這在執行個體後,會産生兩個不同的對象,但是b1.__dict__和b2.__dict__都指向了__shared_state的記憶體位址。

  另外還可以通過__new__來實作單态模式:

class Borg:

    __shared_state = {}

    def __new__(cls, *args, **kwargs):
        obj=super(Borg,cls).__new__(cls, *args, **kwargs)
        obj.__dict__ = obj.__shared_state
        return obj      

作者:iveBoy

出處:http://www.cnblogs.com/shenjianping/

本文版權歸作者和部落格園共有,歡迎轉載,但未經作者同意必須在文章頁面給出原文連接配接,否則保留追究法律責任的權利。

繼續閱讀