單例模式(Singleton Pattern)是一種常用的軟件設計模式,該模式的主要目的是確保某一個類只有一個實例存在。當你希望在整個系統(tǒng)中,某個類只能出現(xiàn)一個實例時,單例對象就能派上用場。
比如,某個服務器程序的配置信息存放在一個文件中,客戶端通過一個 AppConfig 的類來讀取配置文件的信息。如果在程序運行期間,有很多地方都需要使用配置文件的內(nèi)容,也就是說,很多地方都需要創(chuàng)建 AppConfig 對象的實例,這就導致系統(tǒng)中存在多個 AppConfig 的實例對象,而這樣會嚴重浪費內(nèi)存資源,尤其是在配置文件內(nèi)容很多的情況下。事實上,類似 AppConfig 這樣的類,我們希望在程序運行期間只存在一個實例對象
class Singleton(object): def __init__(self): pass def __new__(cls, *args, **kwargs): if not hasattr(Singleton, "_instance"): Singleton._instance = object.__new__(cls) return Singleton._instanceobj1 = Singleton()obj2 = Singleton()print(obj1, obj2) # <__main__.Singleton object at 0x000001F2C74E4D08> <__main__.Singleton object at 0x000001F2C74E4D08>
工廠模式是一個在軟件開發(fā)中用來創(chuàng)建對象的設計模式。
工廠模式包涵一個超類。這個超類提供一個抽象化的接口來創(chuàng)建一個特定類型的對象,而不是決定哪個對象可以被創(chuàng)建。
為了實現(xiàn)此方法,需要創(chuàng)建一個工廠類創(chuàng)建并返回。?
當程序運行輸入一個“類型”的時候,需要創(chuàng)建于此相應的對象。這就用到了工廠模式。在如此情形中,實現(xiàn)代碼基于工廠模式,可以達到可擴展,可維護的代碼。當增加一個新的類型,不在需要修改已存在的類,只增加能夠產(chǎn)生新類型的子類。
簡短的說,當以下情形可以使用工廠模式:
1.不知道用戶想要創(chuàng)建什么樣的對象
2.當你想要創(chuàng)建一個可擴展的關聯(lián)在創(chuàng)建類與支持創(chuàng)建對象的類之間。
一個例子更能很好的理解以上的內(nèi)容:
在程序運行期間,用戶傳遞性別給工廠,工廠創(chuàng)建一個與性別有關的對象。因此工廠類在運行期,決定了哪個對象應該被創(chuàng)建
class Person: def __init__(self): self.name = None self.gender = None def getName(self): return self.name def getGender(self): return self.genderclass Male(Person): def __init__(self, name): print("Hello Mr " name)class Female(Person): def __init__(self, name): print("Hello Miss " name)class Factory: def getPerson(self, name, gender): if gender == "M": return Male(name) if gender == "F": return Female(name)if __name__ == '__main__': factory = Factory() person = factory.getPerson("zhangsan", "M") print(person)
將一個復雜對象的構建與它的表示分離,使得同樣的構建過程可以創(chuàng)建不同的表示。
相關模式:思路和模板方法模式很像,模板方法是封裝算法流程,對某些細節(jié),提供接口由子類修改,建造者模式更為高層一點,將所有細節(jié)都交由子類實現(xiàn)。例如C 模板中可以定義一個類實現(xiàn)數(shù)字可以相加,字符串也可以相加的功能,模板中只要傳入相應的類型底層就可以自動判斷是字符串還是數(shù)字,并且返回指定的結(jié)果
一個例子更能很好的理解以上的內(nèi)容:
1. 有一個接口類,定義創(chuàng)建對象的方法。一個指揮員類,接受創(chuàng)造者對象為參數(shù)。兩個創(chuàng)造者類,創(chuàng)建對象方法相同,內(nèi)部創(chuàng)建可自定義
2.一個指揮員,兩個創(chuàng)造者(瘦子 胖子),指揮員可以指定由哪個創(chuàng)造者來創(chuàng)造
from abc import ABCMeta, abstractmethodclass Builder(): __metaclass__ = ABCMeta @abstractmethod def draw_left_arm(self): pass @abstractmethod def draw_right_arm(self): pass @abstractmethod def draw_left_foot(self): pass @abstractmethod def draw_right_foot(self): pass @abstractmethod def draw_head(self): pass @abstractmethod def draw_body(self): passclass Thin(Builder): def draw_left_arm(self): print("畫左手") def draw_right_arm(self): print("畫右手") def draw_left_foot(self): print("畫左腳") def draw_right_foot(self): print("畫右腳") def draw_head(self): print("畫頭") def draw_body(self): print("畫瘦身體")class Fat(Builder): def draw_left_arm(self): print("畫左手") def draw_right_arm(self): print("畫右手") def draw_left_foot(self): print("畫左腳") def draw_right_foot(self): print("畫右腳") def draw_head(self): print("畫頭") def draw_body(self): print("畫胖身體")class Director(): def __init__(self, person): self.person = person def draw(self): self.person.draw_left_arm() self.person.draw_right_arm() self.person.draw_left_foot() self.person.draw_right_foot() self.person.draw_head() self.person.draw_body()if __name__ == '__main__': thin = Thin() fat = Fat() director_thin = Director(thin) director_thin.draw() director_fat = Director(fat) director_fat.draw()
用原型實例指定創(chuàng)建對象的種類,并且通過拷貝這些原型創(chuàng)建新的對象。
原型模式本質(zhì)就是克隆對象,所以在對象初始化操作比較復雜的情況下,很實用,能大大降低耗時,提高性能,因為“不用重新初始化對象,而是動態(tài)地獲得對象運行時的狀態(tài)”。
淺拷貝(Shallow Copy):指對象的字段被拷貝,而字段引用的對象不會被拷貝,拷貝的對象和源對象只是名稱相同,但是他們共用一個實體。
深拷貝(deep copy):對對象實例中字段引用的對象也進行拷貝。
import copyfrom collections import OrderedDictclass Book: def __init__(self, name, authors, price, **rest): """rest的例子有:出版商,長度,標簽,出版日期""" self.name = name self.authors = authors self.price = price self.__dict__.update(rest) def __str__(self): mylist = [] ordered = OrderedDict(sorted(self.__dict__.items())) for i in ordered.keys(): mylist.append('{}: {}'.format(i, ordered[i])) if i == 'price': mylist.append('$') mylist.append('\n') return ''.join(mylist)class Prototype: def __init__(self): self.objects = dict() def register(self, identifier, obj): self.objects[identifier] = obj def unregister(self, identifier): del self.objects[identifier] def clone(self, identifier, **attr): found = self.objects.get(identifier) if not found: raise ValueError('incorrect object identifier: {}'.format(identifier)) obj = copy.deepcopy(found) obj.__dict__.update(attr) return objdef main(): b1 = Book('The C Programming Language', ('Brian W. Kernighan', 'Dennis M.Ritchie'), price=118, publisher='Prentice Hall', length=228, publication_date='1978-02-22', tags=('C', 'programming', 'algorithms', 'data structures')) prototype = Prototype() cid = 'k&r-first' prototype.register(cid, b1) b2 = prototype.clone(cid, name='The C Programming Language(ANSI)', price=48.99, length=274, publication_date='1988-04-01', edition=2) print(b1) print(b2) print("ID b1 : {} != ID b2 : {}".format(id(b1), id(b2)))if __name__ =='__main__': main()'''C:/Users/wangxianchao/PycharmProjects/PythonStudy/多線程.pyodict_keys(['authors', 'length', 'name', 'price', 'publication_date', 'publisher', 'tags'])authors: ('Brian W. Kernighan', 'Dennis M.Ritchie')length: 228name: The C Programming Languageprice: 118$publication_date: 1978-02-22publisher: Prentice Halltags: ('C', 'programming', 'algorithms', 'data structures')odict_keys(['authors', 'edition', 'length', 'name', 'price', 'publication_date', 'publisher', 'tags'])authors: ('Brian W. Kernighan', 'Dennis M.Ritchie')edition: 2length: 274name: The C Programming Language(ANSI)price: 48.99$publication_date: 1988-04-01publisher: Prentice Halltags: ('C', 'programming', 'algorithms', 'data structures')ID b1 : 1922565623240 != ID b2 : 1922565694600Process finished with exit code 0'''