參考文獻:
《大話設計模式》——吳強
《Python設計模式》——pythontip.com
《23種設計模式》——http://www.cnblogs.com/beijiguangyong/
設計模式是什么?
設計模式是經過總結、優化的,對我們經常會碰到的一些編程問題的可重用解決方案。一個設計模式并不像一個類或一個庫那樣能夠直接作用于我們的代碼。反之,設計模式更為高級,它是一種必須在特定情形下實現的一種方法模板。設計模式不會綁定具體的編程語言。一個好的設計模式應該能夠用大部分編程語言實現(如果做不到全部的話,具體取決于語言特性)。最為重要的是,設計模式也是一把雙刃劍,如果設計模式被用在不恰當的情形下將會造成災難,進而帶來無窮的麻煩。然而如果設計模式在正確的時間被用在正確地地方,它將是你的救星。
起初,你會認為“模式”就是為了解決一類特定問題而特別想出來的明智之舉。說的沒錯,看起來的確是通過很多人一起工作,從不同的角度看待問題進而形成的一個最通用、最靈活的解決方案。也許這些問題你曾經見過或是曾經解決過,但是你的解決方案很可能沒有模式這么完備。
雖然被稱為“設計模式”,但是它們同“設計“領域并非緊密聯系。設計模式同傳統意義上的分析、設計與實現不同,事實上設計模式將一個完整的理念根植于程序中,所以它可能出現在分析階段或是更高層的設計階段。很有趣的是因為設計模式的具體體現是程序代碼,因此可能會讓你認為它不會在具體實現階段之前出現(事實上在進入具體實現階段之前你都沒有意識到正在使用具體的設計模式)。
可以通過程序設計的基本概念來理解模式:增加一個抽象層。抽象一個事物就是隔離任何具體細節,這么做的目的是為了將那些不變的核心部分從其他細節中分離出來。當你發現你程序中的某些部分經常因為某些原因改動,而你不想讓這些改動的部分引發其他部分的改動,這時候你就需要思考那些不會變動的設計方法了。這么做不僅會使代碼可維護性更高,而且會讓代碼更易于理解,從而降低開發成本。
這里列舉了三種最基本的設計模式:
創建模式,提供實例化的方法,為適合的狀況提供相應的對象創建方法。
結構化模式,通常用來處理實體之間的關系,使得這些實體能夠更好地協同工作。
行為模式,用于在不同的實體建進行通信,為實體之間的通信提供更容易,更靈活的通信方法。
創建型
1. Factory Method(工廠方法)
2. Abstract Factory(抽象工廠)
3. Builder(建造者)
4. Prototype(原型)
5. Singleton(單例)
結構型
6. Adapter Class/Object(適配器)
7. Bridge(橋接)
8. Composite(組合)
9. Decorator(裝飾)
10. Facade(外觀)
11. Flyweight(享元)
12. Proxy(代理)
行為型
13. Interpreter(解釋器)
14. Template Method(模板方法)
15. Chain of Responsibility(責任鏈)
16. Command(命令)
17. Iterator(迭代器)
18. Mediator(中介者)
19. Memento(備忘錄)
20. Observer(觀察者)
21. State(狀態)
22. Strategy(策略)
23. Visitor(訪問者)
創建型
1.Factory Method(工廠方法)
意圖:
定義一個用于創建對象的接口,讓子類決定實例化哪一個類。Factory Method?使一個類的實例化延遲到其子類。
適用性:
當一個類不知道它所必須創建的對象的類的時候。
當一個類希望由它的子類來指定它所創建的對象的時候。
當類將創建對象的職責委托給多個幫助子類中的某一個,并且你希望將哪一個幫助子類是代理者這一信息局部化的時候。
實現:
#!/usr/bin/python
#coding:utf8
'''
Factory Method
'''
class?ChinaGetter:
????"""A simple localizer a la gettext"""
????def?__init__(self):
????????self.trans?=?dict(dog=u"小狗", cat=u"小貓")
????def?get(self, msgid):
????????"""We'll punt if we don't have a translation"""
????????try:
????????????return?self.trans[msgid]
????????except?KeyError:
????????????return?str(msgid)
class?EnglishGetter:
????"""Simply echoes the msg ids"""
????def?get(self, msgid):
????????return?str(msgid)
def?get_localizer(language="English"):
????"""The factory method"""
????languages?=?dict(English=EnglishGetter, China=ChinaGetter)
????return?languages[language]()
# Create our localizers
e, g?=?get_localizer("English"), get_localizer("China")
# Localize some text
for?msgid?in?"dog parrot cat bear".split():
????print(e.get(msgid), g.get(msgid))
2. Abstract Factory(抽象工廠)
意圖:
提供一個創建一系列相關或相互依賴對象的接口,而無需指定它們具體的類。
適用性:
?一個系統要獨立于它的產品的創建、組合和表示時。
?一個系統要由多個產品系列中的一個來配置時。
?當你要強調一系列相關的產品對象的設計以便進行聯合使用時。
?當你提供一個產品類庫,而只想顯示它們的接口而不是實現時。
#!/usr/bin/python
#coding:utf8
'''
Abstract Factory
'''
import?random
class?PetShop:
????"""A pet shop"""
????def?__init__(self, animal_factory=None):
????????"""pet_factory is our abstract factory.
????????We can set it at will."""
????????self.pet_factory?=?animal_factory
????def?show_pet(self):
????????"""Creates and shows a pet using the
????????abstract factory"""
????????pet?=?self.pet_factory.get_pet()
????????print("This is a lovely",?str(pet))
????????print("It says", pet.speak())
????????print("It eats",?self.pet_factory.get_food())
# Stuff that our factory makes
class?Dog:
????def?speak(self):
????????return?"woof"
????def?__str__(self):
????????return?"Dog"
class?Cat:
????def?speak(self):
????????return?"meow"
????def?__str__(self):
????????return?"Cat"
# Factory classes
class?DogFactory:
????def?get_pet(self):
????????return?Dog()
????def?get_food(self):
????????return?"dog food"
class?CatFactory:
????def?get_pet(self):
????????return?Cat()
????def?get_food(self):
????????return?"cat food"
# Create the proper family
def?get_factory():
????"""Let's be dynamic!"""
????return?random.choice([DogFactory, CatFactory])()
# Show pets with various factories
if?__name__?==?"__main__":
????shop?=?PetShop()
????for?i?in?range(3):
????????shop.pet_factory?=?get_factory()
????????shop.show_pet()
????????print("="?*?20)
3. Builder(建造者)
意圖:
將一個復雜對象的構建與它的表示分離,使得同樣的構建過程可以創建不同的表示。
適用性:
當創建復雜對象的算法應該獨立于該對象的組成部分以及它們的裝配方式時。
當構造過程必須允許被構造的對象有不同的表示時。
#!/usr/bin/python
#coding:utf8
"""
????Builder
"""
# Director
class?Director(object):
????def?__init__(self):
????????self.builder?=?None
????def?construct_building(self):
????????self.builder.new_building()
????????self.builder.build_floor()
????????self.builder.build_size()
????def?get_building(self):
????????return?self.builder.building
# Abstract Builder
class?Builder(object):
????def?__init__(self):
????????self.building?=?None
????def?new_building(self):
????????self.building?=?Building()
# Concrete Builder
class?BuilderHouse(Builder):
????def?build_floor(self):
????????self.building.floor?=?'One'
????def?build_size(self):
????????self.building.size?=?'Big'
class?BuilderFlat(Builder):
????def?build_floor(self):
????????self.building.floor?=?'More than One'
????def?build_size(self):
????????self.building.size?=?'Small'
# Product
class?Building(object):
????def?__init__(self):
????????self.floor?=?None
????????self.size?=?None
????def?__repr__(self):
????????return?'Floor: %s | Size: %s'?%?(self.floor,?self.size)
# Client
if?__name__?==?"__main__":
????director?=?Director()
????director.builder?=?BuilderHouse()
????director.construct_building()
????building?=?director.get_building()
????print(building)
????director.builder?=?BuilderFlat()
????director.construct_building()
????building?=?director.get_building()
????print(building)
4. Prototype(原型)
意圖:
用原型實例指定創建對象的種類,并且通過拷貝這些原型創建新的對象。
適用性:
當要實例化的類是在運行時刻指定時,例如,通過動態裝載;或者為了避免創建一個與產品類層次平行的工廠類層次時;或者當一個類的實例只能有幾個不同狀態組合中的一種時。建立相應數目的原型并克隆它們可能比每次用合適的狀態手工實例化該類更方便一些。
#!/usr/bin/python
#coding:utf8
'''
Prototype
'''
import?copy
class?Prototype:
????def?__init__(self):
????????self._objects?=?{}
????def?register_object(self, name, obj):
????????"""Register an object"""
????????self._objects[name]?=?obj
????def?unregister_object(self, name):
????????"""Unregister an object"""
????????del?self._objects[name]
????def?clone(self, name,?**attr):
????????"""Clone a registered object and update inner attributes dictionary"""
????????obj?=?copy.deepcopy(self._objects.get(name))
????????obj.__dict__.update(attr)
????????return?obj
def?main():
????class?A:
????????def?__str__(self):
????????????return?"I am A"
????a?=?A()
????prototype?=?Prototype()
????prototype.register_object('a', a)
????b?=?prototype.clone('a', a=1, b=2, c=3)
????print(a)
????print(b.a, b.b, b.c)
if?__name__?==?'__main__':
????main()
5. Singleton(單例)
意圖:
保證一個類僅有一個實例,并提供一個訪問它的全局訪問點。
適用性:
當類只能有一個實例而且客戶可以從一個眾所周知的訪問點訪問它時。
當這個唯一實例應該是通過子類化可擴展的,并且客戶應該無需更改代碼就能使用一個擴展的實例時。
實現:
#!/usr/bin/python
#coding:utf8
'''
Singleton
'''
class?Singleton(object):
????''''' A python style singleton '''
????def?__new__(cls,?*args,?**kw):
????????if?not?hasattr(cls,?'_instance'):
????????????org?=?super(Singleton,?cls)
????????????cls._instance?=?org.__new__(cls,?*args,?**kw)
????????return?cls._instance
if?__name__?==?'__main__':
????class?SingleSpam(Singleton):
????????def?__init__(self, s):
????????????self.s?=?s
????????def?__str__(self):
????????????return?self.s
????s1?=?SingleSpam('spam')
????print?id(s1), s1
????s2?=?SingleSpam('spa')
????print?id(s2), s2
????print?id(s1), s1
結構型
6. Adapter Class/Object(適配器)
意圖:
?將一個類的接口轉換成客戶希望的另外一個接口。Adapter?模式使得原本由于接口不兼容而不能一起工作的那些類可以一起工作。?
適用性:
?你想使用一個已經存在的類,而它的接口不符合你的需求。
你想創建一個可以復用的類,該類可以與其他不相關的類或不可預見的類(即那些接口可能不一定兼容的類)協同工作。
(僅適用于對象Adapter?)你想使用一些已經存在的子類,但是不可能對每一個都進行子類化以匹配它們的接口。對象適配器可以適配它的父類接口。
#!/usr/bin/python
#coding:utf8
'''
Adapter
'''
import?os
class?Dog(object):
????def?__init__(self):
????????self.name?=?"Dog"
????def?bark(self):
????????return?"woof!"
class?Cat(object):
????def?__init__(self):
????????self.name?=?"Cat"
????def?meow(self):
????????return?"meow!"
class?Human(object):
????def?__init__(self):
????????self.name?=?"Human"
????def?speak(self):
????????return?"'hello'"
class?Car(object):
????def?__init__(self):
????????self.name?=?"Car"
????def?make_noise(self, octane_level):
????????return?"vroom%s"?%?("!"?*?octane_level)
class?Adapter(object):
????"""
????Adapts an object by replacing methods.
????Usage:
????dog = Dog
????dog = Adapter(dog, dict(make_noise=dog.bark))
????"""
????def?__init__(self, obj, adapted_methods):
????????"""We set the adapted methods in the object's dict"""
????????self.obj?=?obj
????????self.__dict__.update(adapted_methods)
????def?__getattr__(self, attr):
????????"""All non-adapted calls are passed to the object"""
????????return?getattr(self.obj, attr)
def?main():
????objects?=?[]
????dog?=?Dog()
????objects.append(Adapter(dog,?dict(make_noise=dog.bark)))
????cat?=?Cat()
????objects.append(Adapter(cat,?dict(make_noise=cat.meow)))
????human?=?Human()
????objects.append(Adapter(human,?dict(make_noise=human.speak)))
????car?=?Car()
????car_noise?=?lambda: car.make_noise(3)
????objects.append(Adapter(car,?dict(make_noise=car_noise)))
????for?obj?in?objects:
????????print?"A", obj.name,?"goes", obj.make_noise()
if?__name__?==?"__main__":
????main()
7. Bridge(橋接)
意圖:
?將抽象部分與它的實現部分分離,使它們都可以獨立地變化。
?適用性:
?你不希望在抽象和它的實現部分之間有一個固定的綁定關系。例如這種情況可能是因為,在程序運行時刻實現部分應可以被選擇或者切換。
?類的抽象以及它的實現都應該可以通過生成子類的方法加以擴充。這時Bridge?模式使你可以對不同的抽象接口和實現部分進行組合,并分別對它們進行擴充。
?對一個抽象的實現部分的修改應對客戶不產生影響,即客戶的代碼不必重新編譯。
?(C++)你想對客戶完全隱藏抽象的實現部分。在C++中,類的表示在類接口中是可見的。
?有許多類要生成。這樣一種類層次結構說明你必須將一個對象分解成兩個部分。Rumbaugh?稱這種類層次結構為“嵌套的普化”(nested generalizations?)。
?你想在多個對象間共享實現(可能使用引用計數),但同時要求客戶并不知道這一點。一個簡單的例子便是Coplien?的String?類[ Cop92 ],在這個類中多個對象可以共享同一個字符串表示(StringRep)。
#!/usr/bin/python
#coding:utf8
'''
Bridge
'''
# ConcreteImplementor 1/2
class?DrawingAPI1(object):
????def?draw_circle(self, x, y, radius):
????????print('API1.circle at {}:{} radius {}'.format(x, y, radius))
# ConcreteImplementor 2/2
class?DrawingAPI2(object):
????def?draw_circle(self, x, y, radius):
????????print('API2.circle at {}:{} radius {}'.format(x, y, radius))
# Refined Abstraction
class?CircleShape(object):
????def?__init__(self, x, y, radius, drawing_api):
????????self._x?=?x
????????self._y?=?y
????????self._radius?=?radius
????????self._drawing_api?=?drawing_api
????# low-level i.e. Implementation specific
????def?draw(self):
????????self._drawing_api.draw_circle(self._x,?self._y,?self._radius)
????# high-level i.e. Abstraction specific
????def?scale(self, pct):
????????self._radius?*=?pct
def?main():
????shapes?=?(
????????CircleShape(1,?2,?3, DrawingAPI1()),
????????CircleShape(5,?7,?11, DrawingAPI2())
????)
????for?shape?in?shapes:
????????shape.scale(2.5)
????????shape.draw()
if?__name__?==?'__main__':
????main()
8. Composite(組合)
意圖:
?將對象組合成樹形結構以表示“部分-整體”的層次結構。C o m p o s i t e?使得用戶對單個對象和組合對象的使用具有一致性。?
適用性:
?你想表示對象的部分-整體層次結構。
你希望用戶忽略組合對象與單個對象的不同,用戶將統一地使用組合結構中的所有對象。
#!/usr/bin/python
#coding:utf8
"""
Composite
"""
class?Component:
????def?__init__(self,strName):
????????self.m_strName?=?strName
????def?Add(self,com):
????????pass
????def?Display(self,nDepth):
????????pass
class?Leaf(Component):
????def?Add(self,com):
????????print?"leaf can't add"
????def?Display(self,nDepth):
????????strtemp?=?"-"?*?nDepth
????????strtemp=strtemp+self.m_strName
????????print?strtemp
class?Composite(Component):
????def?__init__(self,strName):
????????self.m_strName?=?strName
????????self.c?=?[]
????def?Add(self,com):
????????self.c.append(com)
????def?Display(self,nDepth):
????????strtemp?=?"-"*nDepth
????????strtemp=strtemp+self.m_strName
????????print?strtemp
????????for?com?in?self.c:
????????????com.Display(nDepth+2)
if?__name__?==?"__main__":
????p?=?Composite("Wong")
????p.Add(Leaf("Lee"))
????p.Add(Leaf("Zhao"))
????p1?=?Composite("Wu")
????p1.Add(Leaf("San"))
????p.Add(p1)
????p.Display(1);
9. Decorator(裝飾)
意圖:
動態地給一個對象添加一些額外的職責。就增加功能來說,Decorator?模式相比生成子類更為靈活。
適用性:
?在不影響其他對象的情況下,以動態、透明的方式給單個對象添加職責。
?處理那些可以撤消的職責。
當不能采用生成子類的方法進行擴充時。一種情況是,可能有大量獨立的擴展,為支持每一種組合將產生大量的子類,使得子類數目呈爆炸性增長。另一種情況可能是因為類定義被隱藏,或類定義不能用于生成子類。
#!/usr/bin/python
#coding:utf8
'''
Decorator
'''
class?foo(object):
????def?f1(self):
????????print("original f1")
????def?f2(self):
????????print("original f2")
class?foo_decorator(object):
????def?__init__(self, decoratee):
????????self._decoratee?=?decoratee
????def?f1(self):
????????print("decorated f1")
????????self._decoratee.f1()
????def?__getattr__(self, name):
????????return?getattr(self._decoratee, name)
u?=?foo()
v?=?foo_decorator(u)
v.f1()
v.f2()
10. Facade(外觀)
意圖:
?為子系統中的一組接口提供一個一致的界面,Facade模式定義了一個高層接口,這個接口使得這一子系統更加容易使用。
適用性:
當你要為一個復雜子系統提供一個簡單接口時。子系統往往因為不斷演化而變得越來越復雜。大多數模式使用時都會產生更多更小的類。這使得子系統更具可重用性,也更容易對子系統進行定制,但這也給那些不需要定制子系統的用戶帶來一些使用上的困難。Facade?可以提供一個簡單的缺省視圖,這一視圖對大多數用戶來說已經足夠,而那些需要更多的可定制性的用戶可以越過facade層。
客戶程序與抽象類的實現部分之間存在著很大的依賴性。引入facade?將這個子系統與客戶以及其他的子系統分離,可以提高子系統的獨立性和可移植性。
當你需要構建一個層次結構的子系統時,使用facade模式定義子系統中每層的入口點。如果子系統之間是相互依賴的,你可以讓它們僅通過facade進行通訊,從而簡化了它們之間的依賴關系。
#!/usr/bin/python
#coding:utf8
'''
Decorator
'''
import?time
SLEEP?=?0.5
# Complex Parts
class?TC1:
????def?run(self):
????????print("###### In Test 1 ######")
????????time.sleep(SLEEP)
????????print("Setting up")
????????time.sleep(SLEEP)
????????print("Running test")
????????time.sleep(SLEEP)
????????print("Tearing down")
????????time.sleep(SLEEP)
????????print("Test Finished\n")
class?TC2:
????def?run(self):
????????print("###### In Test 2 ######")
????????time.sleep(SLEEP)
????????print("Setting up")
????????time.sleep(SLEEP)
????????print("Running test")
????????time.sleep(SLEEP)
????????print("Tearing down")
????????time.sleep(SLEEP)
????????print("Test Finished\n")
class?TC3:
????def?run(self):
????????print("###### In Test 3 ######")
????????time.sleep(SLEEP)
????????print("Setting up")
????????time.sleep(SLEEP)
????????print("Running test")
????????time.sleep(SLEEP)
????????print("Tearing down")
????????time.sleep(SLEEP)
????????print("Test Finished\n")
# Facade
class?TestRunner:
????def?__init__(self):
????????self.tc1?=?TC1()
????????self.tc2?=?TC2()
????????self.tc3?=?TC3()
????????self.tests?=?[i?for?i?in?(self.tc1,?self.tc2,?self.tc3)]
????def?runAll(self):
????????[i.run()?for?i?in?self.tests]
# Client
if?__name__?==?'__main__':
????testrunner?=?TestRunner()
????testrunner.runAll()
11. Flyweight(享元)
意圖:
運用共享技術有效地支持大量細粒度的對象。
適用性:
一個應用程序使用了大量的對象。
完全由于使用大量的對象,造成很大的存儲開銷。
對象的大多數狀態都可變為外部狀態。
如果刪除對象的外部狀態,那么可以用相對較少的共享對象取代很多組對象。?
應用程序不依賴于對象標識。由于Flyweight?對象可以被共享,對于概念上明顯有別的對象,標識測試將返回真值。
#!/usr/bin/python
#coding:utf8
'''
Flyweight
'''
import?weakref?
class?Card(object):
????"""The object pool. Has builtin reference counting"""
????_CardPool?=?weakref.WeakValueDictionary()
????"""Flyweight implementation. If the object exists in the
????pool just return it (instead of creating a new one)"""
????def?__new__(cls, value, suit):????????
????????obj?=?Card._CardPool.get(value?+?suit,?None)????????
????????if?not?obj:????????????
????????????obj?=?object.__new__(cls)????????????
????????????Card._CardPool[value?+?suit]?=?obj????????????
????????????obj.value, obj.suit?=?value, suit?????????
????????return?obj
????# def __init__(self, value, suit):????????
????#???? self.value, self.suit = value, suit?????
????def?__repr__(self):????????
????????return?""?%?(self.value,?self.suit)?????
if?__name__?==?'__main__':
????# comment __new__ and uncomment __init__ to see the difference
????c1?=?Card('9',?'h')
????c2?=?Card('9',?'h')
????print(c1, c2)
????print(c1?==?c2)
????print(id(c1),?id(c2))
12. Proxy(代理)
意圖:
為其他對象提供一種代理以控制對這個對象的訪問。
適用性:
?在需要用比較通用和復雜的對象指針代替簡單的指針的時候,使用Proxy模式。下面是一?些可以使用Proxy?模式常見情況:?
1)?遠程代理(Remote Proxy?)為一個對象在不同的地址空間提供局部代表。?NEXTSTEP[Add94]?使用NXProxy?類實現了這一目的。Coplien[Cop92]?稱這種代理為“大使”?(Ambassador?)。
2 )虛代理(Virtual Proxy?)根據需要創建開銷很大的對象。在動機一節描述的ImageProxy?就是這樣一種代理的例子。
3)?保護代理(Protection Proxy?)控制對原始對象的訪問。保護代理用于對象應該有不同?的訪問權限的時候。例如,在Choices?操作系統[ CIRM93]中KemelProxies為操作系統對象提供?了訪問保護。
4 )智能指引(Smart Reference?)取代了簡單的指針,它在訪問對象時執行一些附加操作。?它的典型用途包括:對指向實際對象的引用計數,這樣當該對象沒有引用時,可以自動釋放它(也稱為SmartPointers[Ede92 ] )。
?當第一次引用一個持久對象時,將它裝入內存。
?在訪問一個實際對象前,檢查是否已經鎖定了它,以確保其他對象不能改變它。
#!/usr/bin/python
#coding:utf8
'''
Proxy
'''
import?time
class?SalesManager:
????def?work(self):
????????print("Sales Manager working...")
????def?talk(self):
????????print("Sales Manager ready to talk")
class?Proxy:
????def?__init__(self):
????????self.busy?=?'No'
????????self.sales?=?None
????def?work(self):
????????print("Proxy checking for Sales Manager availability")
????????if?self.busy?==?'No':
????????????self.sales?=?SalesManager()
????????????time.sleep(2)
????????????self.sales.talk()
????????else:
????????????time.sleep(2)
????????????print("Sales Manager is busy")
if?__name__?==?'__main__':
????p?=?Proxy()
????p.work()
????p.busy?=?'Yes'
????p.work()
行為型
13. Interpreter(解釋器)
意圖:
給定一個語言,定義它的文法的一種表示,并定義一個解釋器,這個解釋器使用該表示來解釋語言中的句子。
適用性:
當有一個語言需要解釋執行,?并且你可將該語言中的句子表示為一個抽象語法樹時,可使用解釋器模式。而當存在以下情況時該模式效果最好:
該文法簡單對于復雜的文法,?文法的類層次變得龐大而無法管理。此時語法分析程序生成器這樣的工具是更好的選擇。它們無需構建抽象語法樹即可解釋表達式,?這樣可以節省空間而且還可能節省時間。
效率不是一個關鍵問題最高效的解釋器通常不是通過直接解釋語法分析樹實現的,?而是首先將它們轉換成另一種形式。例如,正則表達式通常被轉換成狀態機。但即使在這種情況下,?轉換器仍可用解釋器模式實現,?該模式仍是有用的。
#!/usr/bin/python
#coding:utf8
'''
Interpreter
'''
class?Context:
????def?__init__(self):
????????self.input=""
????????self.output=""
class?AbstractExpression:
????def?Interpret(self,context):
????????pass
class?Expression(AbstractExpression):
????def?Interpret(self,context):
????????print?"terminal interpret"
class?NonterminalExpression(AbstractExpression):
????def?Interpret(self,context):
????????print?"Nonterminal interpret"
if?__name__?==?"__main__":
????context=?""
????c?=?[]
????c?=?c?+?[Expression()]
????c?=?c?+?[NonterminalExpression()]
????c?=?c?+?[Expression()]
????c?=?c?+?[Expression()]
????for?a?in?c:
????????a.Interpret(context)
14. Template Method(模板方法)
意圖:
定義一個操作中的算法的骨架,而將一些步驟延遲到子類中。TemplateMethod?使得子類可以不改變一個算法的結構即可重定義該算法的某些特定步驟。
適用性:
一次性實現一個算法的不變的部分,并將可變的行為留給子類來實現。
各子類中公共的行為應被提取出來并集中到一個公共父類中以避免代碼重復。這是Opdyke?和Johnson所描述過的“重分解以一般化”的一個很好的例子[ OJ93 ]。首先識別現有代碼中的不同之處,并且將不同之處分離為新的操作。最后,用一個調用這些新的操作的模板方法來替換這些不同的代碼。
控制子類擴展。模板方法只在特定點調用“hook ”操作(參見效果一節),這樣就只允許在這些點進行擴展。
#!/usr/bin/python
#coding:utf8
'''
Template Method
'''
ingredients?=?"spam eggs apple"
line?=?'-'?*?10
# Skeletons
def?iter_elements(getter, action):????
????"""Template skeleton that iterates items"""
????for?element?in?getter():????????
????????action(element)????
????????print(line)?
def?rev_elements(getter, action):
????"""Template skeleton that iterates items in reverse order"""
????for?element?in?getter()[::-1]:????????
????????action(element)????
????????print(line)?
# Getters
def?get_list():????
????return?ingredients.split()?
def?get_lists():
????return?[list(x)?for?x?in?ingredients.split()]?
# Actions
def?print_item(item):????
????print(item)?
def?reverse_item(item):
????print(item[::-1])?
# Makes templates
def?make_template(skeleton, getter, action):????
????"""Instantiate a template method with getter and action"""
????def?template():????????
????????skeleton(getter, action)????
????return?template?
# Create our template functions
templates?=?[make_template(s, g, a)?????????????
?????????????for?g?in?(get_list, get_lists)?????????????
?????????????for?a?in?(print_item, reverse_item)?????????????
?????????????for?s?in?(iter_elements, rev_elements)]?
# Execute them
for?template?in?templates:????
????template()
15. Chain of Responsibility(責任鏈)
意圖:
?使多個對象都有機會處理請求,從而避免請求的發送者和接收者之間的耦合關系。將這些對象連成一條鏈,并沿著這條鏈傳遞該請求,直到有一個對象處理它為止。
適用性:
?有多個的對象可以處理一個請求,哪個對象處理該請求運行時刻自動確定。
?你想在不明確指定接收者的情況下,向多個對象中的一個提交一個請求。
?可處理一個請求的對象集合應被動態指定。
#!/usr/bin/python
#coding:utf8
"""
Chain
"""
class?Handler:
????def?successor(self, successor):
????????self.successor?=?successor
class?ConcreteHandler1(Handler):
????def?handle(self, request):
????????if?request >?0?and?request <=?10:
????????????print("in handler1")
????????else:
????????????self.successor.handle(request)
class?ConcreteHandler2(Handler):
????def?handle(self, request):
????????if?request >?10?and?request <=?20:
????????????print("in handler2")
????????else:
????????????self.successor.handle(request)
class?ConcreteHandler3(Handler):
????def?handle(self, request):
????????if?request >?20?and?request <=?30:
????????????print("in handler3")
????????else:
????????????print('end of chain, no handler for {}'.format(request))
class?Client:
????def?__init__(self):
????????h1?=?ConcreteHandler1()
????????h2?=?ConcreteHandler2()
????????h3?=?ConcreteHandler3()
????????h1.successor(h2)
????????h2.successor(h3)
????????requests?=?[2,?5,?14,?22,?18,?3,?35,?27,?20]
????????for?request?in?requests:
????????????h1.handle(request)
if?__name__?==?"__main__":
????client?=?Client()
16. Command(命令)
意圖:
將一個請求封裝為一個對象,從而使你可用不同的請求對客戶進行參數化;對請求排隊或記錄請求日志,以及支持可撤消的操作。
適用性:
抽象出待執行的動作以參數化某對象,你可用過程語言中的回調(call back)函數表達這種參數化機制。所謂回調函數是指函數先在某處注冊,而它將在稍后某個需要的時候被調用。Command?模式是回調機制的一個面向對象的替代品。
在不同的時刻指定、排列和執行請求。一個Command對象可以有一個與初始請求無關的生存期。如果一個請求的接收者可用一種與地址空間無關的方式表達,那么就可將負責該請求的命令對象傳送給另一個不同的進程并在那兒實現該請求。
支持取消操作。Command的Excute?操作可在實施操作前將狀態存儲起來,在取消操作時這個狀態用來消除該操作的影響。Command?接口必須添加一個Unexecute操作,該操作取消上一次Execute調用的效果。執行的命令被存儲在一個歷史列表中??赏ㄟ^向后和向前遍歷這一列表并分別調用Unexecute和Execute來實現重數不限的“取消”和“重做”。
支持修改日志,這樣當系統崩潰時,這些修改可以被重做一遍。在Command接口中添加裝載操作和存儲操作,可以用來保持變動的一個一致的修改日志。從崩潰中恢復的過程包括從磁盤中重新讀入記錄下來的命令并用Execute操作重新執行它們。
用構建在原語操作上的高層操作構造一個系統。這樣一種結構在支持事務( transaction)的信息系統中很常見。一個事務封裝了對數據的一組變動。Command模式提供了對事務進行建模的方法。Command有一個公共的接口,使得你可以用同一種方式調用所有的事務。同時使用該模式也易于添加新事務以擴展系統。
#!/usr/bin/python
#coding:utf8
"""
Command
"""
import?os
class?MoveFileCommand(object):
????def?__init__(self, src, dest):
????????self.src?=?src
????????self.dest?=?dest
????def?execute(self):
????????self()
????def?__call__(self):
????????print('renaming {} to {}'.format(self.src,?self.dest))
????????os.rename(self.src,?self.dest)
????def?undo(self):
????????print('renaming {} to {}'.format(self.dest,?self.src))
????????os.rename(self.dest,?self.src)
if?__name__?==?"__main__":
????command_stack?=?[]
????# commands are just pushed into the command stack
????command_stack.append(MoveFileCommand('foo.txt',?'bar.txt'))
????command_stack.append(MoveFileCommand('bar.txt',?'baz.txt'))
????# they can be executed later on
????for?cmd?in?command_stack:
????????cmd.execute()
????# and can also be undone at will
????for?cmd?in?reversed(command_stack):
????????cmd.undo()
17. Iterator(迭代器)
意圖:
提供一種方法順序訪問一個聚合對象中各個元素,?而又不需暴露該對象的內部表示。
適用性:
訪問一個聚合對象的內容而無需暴露它的內部表示。
支持對聚合對象的多種遍歷。
為遍歷不同的聚合結構提供一個統一的接口(即,?支持多態迭代)。
#!/usr/bin/python
#coding:utf8
'''
Interator
'''
def?count_to(count):
????"""Counts by word numbers, up to a maximum of five"""
????numbers?=?["one",?"two",?"three",?"four",?"five"]
????# enumerate() returns a tuple containing a count (from start which
????# defaults to 0) and the values obtained from iterating over sequence
????for?pos, number?in?zip(range(count), numbers):
????????yield?number
# Test the generator
count_to_two?=?lambda: count_to(2)
count_to_five?=?lambda: count_to(5)
print('Counting to two...')
for?number?in?count_to_two():
????print?number
print?" "
print('Counting to five...')
for?number?in?count_to_five():
????print?number
print?" "
18. Mediator(中介者)
意圖:
用一個中介對象來封裝一系列的對象交互。中介者使各對象不需要顯式地相互引用,從而使其耦合松散,而且可以獨立地改變它們之間的交互。
適用性:
一組對象以定義良好但是復雜的方式進行通信。產生的相互依賴關系結構混亂且難以理解。
一個對象引用其他很多對象并且直接與這些對象通信,導致難以復用該對象。
想定制一個分布在多個類中的行為,而又不想生成太多的子類。
#!/usr/bin/python
#coding:utf8
'''
Mediator
'''
"""http://dpip.testingperspective.com/?p=28"""
import?time
class?TC:
????def?__init__(self):
????????self._tm?=?tm
????????self._bProblem?=?0
????def?setup(self):
????????print("Setting up the Test")
????????time.sleep(1)
????????self._tm.prepareReporting()
????def?execute(self):
????????if?not?self._bProblem:
????????????print("Executing the test")
????????????time.sleep(1)
????????else:
????????????print("Problem in setup. Test not executed.")
????def?tearDown(self):
????????if?not?self._bProblem:
????????????print("Tearing down")
????????????time.sleep(1)
????????????self._tm.publishReport()
????????else:
????????????print("Test not executed. No tear down required.")
????def?setTM(self, TM):
????????self._tm?=?tm
????def?setProblem(self, value):
????????self._bProblem?=?value
class?Reporter:
????def?__init__(self):
????????self._tm?=?None
????def?prepare(self):
????????print("Reporter Class is preparing to report the results")
????????time.sleep(1)
????def?report(self):
????????print("Reporting the results of Test")
????????time.sleep(1)
????def?setTM(self, TM):
????????self._tm?=?tm
class?DB:
????def?__init__(self):
????????self._tm?=?None
????def?insert(self):
????????print("Inserting the execution begin status in the Database")
????????time.sleep(1)
????????#Following code is to simulate a communication from DB to TC
????????import?random
????????if?random.randrange(1,?4)?==?3:
????????????return?-1
????def?update(self):
????????print("Updating the test results in Database")
????????time.sleep(1)
????def?setTM(self, TM):
????????self._tm?=?tm
class?TestManager:
????def?__init__(self):
????????self._reporter?=?None
????????self._db?=?None
????????self._tc?=?None
????def?prepareReporting(self):
????????rvalue?=?self._db.insert()
????????if?rvalue?==?-1:
????????????self._tc.setProblem(1)
????????????self._reporter.prepare()
????def?setReporter(self, reporter):
????????self._reporter?=?reporter
????def?setDB(self, db):
????????self._db?=?db
????def?publishReport(self):
????????self._db.update()
????????rvalue?=?self._reporter.report()
????def?setTC(self, tc):
????????self._tc?=?tc
if?__name__?==?'__main__':
????reporter?=?Reporter()
????db?=?DB()
????tm?=?TestManager()
????tm.setReporter(reporter)
????tm.setDB(db)
????reporter.setTM(tm)
????db.setTM(tm)
????# For simplification we are looping on the same test.
????# Practically, it could be about various unique test classes and their
????# objects
????while?(True):
????????tc?=?TC()
????????tc.setTM(tm)
????????tm.setTC(tc)
????????tc.setup()
????????tc.execute()
????????tc.tearDown()
19. Memento(備忘錄)
意圖:
在不破壞封裝性的前提下,捕獲一個對象的內部狀態,并在該對象之外保存這個狀態。這樣以后就可將該對象恢復到原先保存的狀態。
適用性:
必須保存一個對象在某一個時刻的(部分)狀態,?這樣以后需要時它才能恢復到先前的狀態。
如果一個用接口來讓其它對象直接得到這些狀態,將會暴露對象的實現細節并破壞對象的封裝性。
#!/usr/bin/python
#coding:utf8
'''
Memento
'''
import?copy
def?Memento(obj, deep=False):
????state?=?(copy.copy, copy.deepcopy)[bool(deep)](obj.__dict__)
????def?Restore():
????????obj.__dict__.clear()
????????obj.__dict__.update(state)
????return?Restore
class?Transaction:
????"""A transaction guard. This is really just
??????syntactic suggar arount a memento closure.
??????"""
????deep?=?False
????def?__init__(self,?*targets):
????????self.targets?=?targets
????????self.Commit()
????def?Commit(self):
????????self.states?=?[Memento(target,?self.deep)?for?target?in?self.targets]
????def?Rollback(self):
????????for?st?in?self.states:
????????????st()
class?transactional(object):
????"""Adds transactional semantics to methods. Methods decorated? with
????@transactional will rollback to entry state upon exceptions.
????"""
????def?__init__(self, method):
????????self.method?=?method
????def?__get__(self, obj, T):
????????def?transaction(*args,?**kwargs):
????????????state?=?Memento(obj)
????????????try:
????????????????return?self.method(obj,?*args,?**kwargs)
????????????except:
????????????????state()
????????????????raise
????????return?transaction
class?NumObj(object):
????def?__init__(self, value):
????????self.value?=?value
????def?__repr__(self):
????????return?'<%s: %r>'?%?(self.__class__.__name__,?self.value)
????def?Increment(self):
????????self.value?+=?1
????@transactional
????def?DoStuff(self):
????????self.value?=?'1111'?# <- invalid value
????????self.Increment()?# <- will fail and rollback
if?__name__?==?'__main__':
????n?=?NumObj(-1)
????print(n)
????t?=?Transaction(n)
????try:
????????for?i?in?range(3):
????????????n.Increment()
????????????print(n)
????????t.Commit()
????????print('-- commited')
????????for?i?in?range(3):
????????????n.Increment()
????????????print(n)
????????n.value?+=?'x'?# will fail
????????print(n)
????except:
????????t.Rollback()
????????print('-- rolled back')
????print(n)
????print('-- now doing stuff ...')
????try:
????????n.DoStuff()
????except:
????????print('-> doing stuff failed!')
????????import?traceback
????????traceback.print_exc(0)
????????pass
????print(n)
20. Observer(觀察者)
意圖:
定義對象間的一種一對多的依賴關系,當一個對象的狀態發生改變時,?所有依賴于它的對象都得到通知并被自動更新。
適用性:
當一個抽象模型有兩個方面,?其中一個方面依賴于另一方面。將這二者封裝在獨立的對象中以使它們可以各自獨立地改變和復用。
當對一個對象的改變需要同時改變其它對象,?而不知道具體有多少對象有待改變。
當一個對象必須通知其它對象,而它又不能假定其它對象是誰。換言之,?你不希望這些對象是緊密耦合的。
#!/usr/bin/python
#coding:utf8
'''
Observer
'''
class?Subject(object):
????def?__init__(self):
????????self._observers?=?[]
????def?attach(self, observer):
????????if?not?observer?in?self._observers:
????????????self._observers.append(observer)
????def?detach(self, observer):
????????try:
????????????self._observers.remove(observer)
????????except?ValueError:
????????????pass
????def?notify(self, modifier=None):
????????for?observer?in?self._observers:
????????????if?modifier !=?observer:
????????????????observer.update(self)
# Example usage
class?Data(Subject):
????def?__init__(self, name=''):
????????Subject.__init__(self)
????????self.name?=?name
????????self._data?=?0
????@property
????def?data(self):
????????return?self._data
????@data.setter
????def?data(self, value):
????????self._data?=?value
????????self.notify()
class?HexViewer:
????def?update(self, subject):
????????print('HexViewer: Subject %s has data 0x%x'?%
??????????????(subject.name, subject.data))
class?DecimalViewer:
????def?update(self, subject):
????????print('DecimalViewer: Subject %s has data %d'?%
??????????????(subject.name, subject.data))
# Example usage...
def?main():
????data1?=?Data('Data 1')
????data2?=?Data('Data 2')
????view1?=?DecimalViewer()
????view2?=?HexViewer()
????data1.attach(view1)
????data1.attach(view2)
????data2.attach(view2)
????data2.attach(view1)
????print("Setting Data 1 = 10")
????data1.data?=?10
????print("Setting Data 2 = 15")
????data2.data?=?15
????print("Setting Data 1 = 3")
????data1.data?=?3
????print("Setting Data 2 = 5")
????data2.data?=?5
????print("Detach HexViewer from data1 and data2.")
????data1.detach(view2)
????data2.detach(view2)
????print("Setting Data 1 = 10")
????data1.data?=?10
????print("Setting Data 2 = 15")
????data2.data?=?15
if?__name__?==?'__main__':
????main()
21. State(狀態)
意圖:
?允許一個對象在其內部狀態改變時改變它的行為。對象看起來似乎修改了它的類。
適用性:
?一個對象的行為取決于它的狀態,?并且它必須在運行時刻根據狀態改變它的行為。
?一個操作中含有龐大的多分支的條件語句,且這些分支依賴于該對象的狀態。這個狀態通常用一個或多個枚舉常量表示。通常,?有多個操作包含這一相同的條件結構。State模式將每一個條件分支放入一個獨立的類中。這使得你可以根據對象自身的情況將對象的狀態作為一個對象,這一對象可以不依賴于其他對象而獨立變化。
#!/usr/bin/python
#coding:utf8
'''
State
'''
class?State(object):
????"""Base state. This is to share functionality"""
????def?scan(self):
????????"""Scan the dial to the next station"""
????????self.pos?+=?1
????????if?self.pos?==?len(self.stations):
????????????self.pos?=?0
????????print("Scanning... Station is",?self.stations[self.pos],?self.name)
class?AmState(State):
????def?__init__(self, radio):
????????self.radio?=?radio
????????self.stations?=?["1250",?"1380",?"1510"]
????????self.pos?=?0
????????self.name?=?"AM"
????def?toggle_amfm(self):
????????print("Switching to FM")
????????self.radio.state?=?self.radio.fmstate
class?FmState(State):
????def?__init__(self, radio):
????????self.radio?=?radio
????????self.stations?=?["81.3",?"89.1",?"103.9"]
????????self.pos?=?0
????????self.name?=?"FM"
????def?toggle_amfm(self):
????????print("Switching to AM")
????????self.radio.state?=?self.radio.amstate
class?Radio(object):
????"""A radio.???? It has a scan button, and an AM/FM toggle switch."""
????def?__init__(self):
????????"""We have an AM state and an FM state"""
????????self.amstate?=?AmState(self)
????????self.fmstate?=?FmState(self)
????????self.state?=?self.amstate
????def?toggle_amfm(self):
????????self.state.toggle_amfm()
????def?scan(self):
????????self.state.scan()
# Test our radio out
if?__name__?==?'__main__':
????radio?=?Radio()
????actions?=?[radio.scan]?*?2?+?[radio.toggle_amfm]?+?[radio.scan]?*?2
????actions?=?actions?*?2
????for?action?in?actions:
????????action()
22. Strategy(策略)
意圖:
?定義一系列的算法,把它們一個個封裝起來,?并且使它們可相互替換。本模式使得算法可獨立于使用它的客戶而變化。
適用性:
?許多相關的類僅僅是行為有異。“策略”提供了一種用多個行為中的一個行為來配置一個類的方法。
?需要使用一個算法的不同變體。例如,你可能會定義一些反映不同的空間/時間權衡的算法。當這些變體實現為一個算法的類層次時[H087] ,可以使用策略模式。
?算法使用客戶不應該知道的數據??墒褂貌呗阅J揭员苊獗┞稄碗s的、與算法相關的數據結構。
?一個類定義了多種行為,?并且這些行為在這個類的操作中以多個條件語句的形式出現。將相關的條件分支移入它們各自的Strategy類中以代替這些條件語句。
#!/usr/bin/python
#coding:utf8
"""
Strategy
In most of other languages Strategy pattern is implemented via creating some base strategy interface/abstract class and
subclassing it with a number of concrete strategies (as we can see at http://en.wikipedia.org/wiki/Strategy_pattern),
however Python supports higher-order functions and allows us to have only one class and inject functions into it's
instances, as shown in this example.
"""
import?types
class?StrategyExample:
????def?__init__(self, func=None):
????????self.name?=?'Strategy Example 0'
????????if?func?is?not?None:
????????????self.execute?=?types.MethodType(func,?self)?????
????def?execute(self):????????
????????print(self.name)??
def?execute_replacement1(self):
????print(self.name?+?' from execute 1')??
def?execute_replacement2(self):
????print(self.name?+?' from execute 2')?
if?__name__?==?'__main__':
????strat0?=?StrategyExample()????
????strat1?=?StrategyExample(execute_replacement1)
????strat1.name?=?'Strategy Example 1'
????strat2?=?StrategyExample(execute_replacement2)
????strat2.name?=?'Strategy Example 2'
????strat0.execute()
????strat1.execute()????
????strat2.execute()
23. Visitor(訪問者)
意圖:
?定義一個操作中的算法的骨架,而將一些步驟延遲到子類中。TemplateMethod?使得子類可以不改變一個算法的結構即可重定義該算法的某些特定步驟。
適用性:
?一次性實現一個算法的不變的部分,并將可變的行為留給子類來實現。
?各子類中公共的行為應被提取出來并集中到一個公共父類中以避免代碼重復。這是Opdyke和Johnson所描述過的“重分解以一般化”的一個很好的例子[OJ93]。首先識別現有代碼中的不同之處,并且將不同之處分離為新的操作。最后,用一個調用這些新的操作的模板方法來替換這些不同的代碼。
?控制子類擴展。模板方法只在特定點調用“hook ”操作(參見效果一節),這樣就只允許在這些點進行擴展。
#!/usr/bin/python
#coding:utf8
'''
Visitor
'''
class?Node(object):
????pass
class?A(Node):
????pass
class?B(Node):
????pass
class?C(A, B):
????pass
class?Visitor(object):
????def?visit(self, node,?*args,?**kwargs):
????????meth?=?None
????????for?cls?in?node.__class__.__mro__:
????????????meth_name?=?'visit_'+cls.__name__
????????????meth?=?getattr(self, meth_name,?None)
????????????if?meth:
????????????????break
????????if?not?meth:
????????????meth?=?self.generic_visit
????????return?meth(node,?*args,?**kwargs)
????def?generic_visit(self, node,?*args,?**kwargs):
????????print('generic_visit '+node.__class__.__name__)
????def?visit_B(self, node,?*args,?**kwargs):
????????print('visit_B '+node.__class__.__name__)
a?=?A()
b?=?B()
c?=?C()
visitor?=?Visitor()
visitor.visit(a)
visitor.visit(b)
visitor.visit(c)