《大話設(shè)計模式》這本書買了很久盔憨,但是一直沒有堅持看完。畢業(yè)之后讯沈,丟了很多書在學(xué)校郁岩,但是這本書沒有舍得丟下。現(xiàn)在看來當初是明智的,再次閱讀的時候问慎,才發(fā)現(xiàn)這本書淺顯易懂萍摊,有趣,通過一個個小故事如叼,緩緩道來設(shè)計模式的妙用冰木。在閱讀的時候,有很多的收獲笼恰,其實說的這些模式踊沸,雖然沒有真正的去了解,但是發(fā)現(xiàn)在開發(fā)過程中社证,很多都是常用到的逼龟,沒有總結(jié)出來而已。在閱讀的過程中追葡,很多時候有感审轮,但是又覺得差一點就能突破。在這里做下閱讀筆記辽俗,算是閱讀的輸出。
原書中的代碼都是用C#是實現(xiàn)的篡诽,在閱讀的過程中崖飘,我根據(jù)對Python的掌握進行了轉(zhuǎn)換。 demo倉庫地址
設(shè)計模式的基本原則
開放-封閉原則
對于拓展是開放的杈女,對于更改是封閉的朱浴。
無論模塊是多么的封閉,都會存在一些無法對之封閉的變化达椰,既然不可能完全封閉翰蠢,設(shè)計人員必須對于他設(shè)計的模塊應(yīng)該對哪種變化做出選擇。他必須先猜測出最有可能發(fā)生的種類啰劲,然后構(gòu)造抽象來隔離那些變化梁沧。
面對需求,對程序的改動是通過新代碼進行的蝇裤,而不是更改現(xiàn)有的代碼廷支。
拒絕不成熟的抽象和抽象本省一樣重要。
單一職責(zé)原則
就一個類而言栓辜,應(yīng)該僅有一個引起它變化的原因恋拍。
軟件設(shè)計真正要做的許多內(nèi)容,就是發(fā)現(xiàn)職責(zé)并把這些職責(zé)分離藕甩。其實要去判斷是否應(yīng)該分離出類來施敢,也不難,那就是你能夠想到對于一個動機去改變一個類,那么這個類就是具有多于一個的職責(zé)僵娃。
依賴倒轉(zhuǎn)原則
A概作、高層模塊不應(yīng)該依賴低層模塊,兩個都應(yīng)該依賴抽象
B悯许、抽象不應(yīng)該依賴細節(jié)仆嗦。細節(jié)應(yīng)該依賴抽象。
依賴倒轉(zhuǎn)原則其實可以說是面向?qū)ο笤O(shè)計的標志先壕,用哪種語言來寫程序不重要瘩扼,如果編寫時,考慮都是如何針對抽象編程而不是針對細節(jié)編程垃僚,即程序中所有的依賴關(guān)系都是終止于抽象類集绰,或者接口,那就是面向?qū)ο蟮脑O(shè)計谆棺,反之就是過程化的設(shè)計了栽燕。
里氏替換原則
子類必須能夠替換掉它們的父類。換句話你說改淑,任何基類可以出現(xiàn)的地方碍岔,子類一定可以出現(xiàn)。 里氏替換原則是繼承復(fù)用的基石朵夏,只有當衍生類可以替換基類蔼啦,軟件單位的功能不受到影響時,基類才能真正被復(fù)用仰猖,而衍生類也能夠在基類的基礎(chǔ)上增加新的行為捏肢。
里氏代換原則是對“開-閉”原則的補充。實現(xiàn)“開閉”原則的關(guān)鍵步驟就是抽象化饥侵。而基類與子類的繼承關(guān)系就是抽象化的具體實現(xiàn)鸵赫,所以里氏代換原則是對實現(xiàn)抽象化的具體步驟的規(guī)范。里氏替換原則中躏升,子類對父類的方法盡量不要重寫和重載辩棒。因為父類代表了定義好的結(jié)構(gòu),通過這個規(guī)范的接口與外界交互煮甥,子類不應(yīng)該隨便破壞它盗温。
迪米特法則(最少知道原則)
一個類對自己依賴的類知道的越少越好。
無論被依賴的類多么復(fù)雜成肘,都應(yīng)該將邏輯封裝在方法的內(nèi)部卖局,通過公用方法提供給外部。這樣當被依賴的類變化時双霍,才能最少的影響該類砚偶。
最少知道原則的另外一個表達方式是:只與直接的朋友通信批销,類之間只要有耦合關(guān)系,就叫朋友關(guān)系染坯。耦合分為依賴均芽、關(guān)聯(lián)、聚合单鹿、組合等掀宋。我們稱出現(xiàn)為成員變量、方法參數(shù)仲锄、方法返回值中的類為直接朋友劲妙。局部變量、臨時變量則不是直接關(guān)系儒喊。我們要求陌生的類不要作為局部變量出現(xiàn)在類中镣奋。
迪米特法則是面向?qū)ο蟮母舅枷耄菑娬{(diào)了類的松耦合關(guān)系怀愧。類之間的耦合越弱侨颈,越有利于復(fù)用,一個處在弱耦合的類被修改芯义,不會對關(guān)系的類造成波及哈垢。
合成復(fù)用原則
盡量首先使用合成\聚合的方式,而不是使用繼承扛拨。
設(shè)計模式分類:
- 創(chuàng)建型模式温赔,共五種:工廠方法模式、抽象工廠模式鬼癣、單例模式、建造者模式啤贩、原型模式待秃。
- 結(jié)構(gòu)型模式,共七種:適配器模式痹屹、裝飾器模式章郁、代理模式、外觀模式志衍、橋接模式暖庄、組合模式、享元模式楼肪。
- 行為型模式培廓,共十一種:策略模式、模板方法模式春叫、觀察者模式肩钠、迭代器模式泣港、職責(zé)鏈模式、命令模式价匠、備忘錄模式当纱、狀態(tài)模式、訪問者模式踩窖、中介者模式坡氯、解釋器模式。
參考
設(shè)計模式詳述
源碼倉庫https://github.com/suAdminWen/studyForPython/tree/master/design_patterns/dahua
簡單工廠模式
>>> oper = OperationFactory.create_operate('+')
>>> oper.number1 = 12
>>> oper.number2 = 13
>>> oper.get_result()
25
>>> oper = OperationFactory.create_operate('/')
>>> oper.number1 = 12
>>> oper.number2 = 0
>>> oper.get_result()
Traceback (most recent call last):
...
ValueError: 除數(shù)不能為0
策略模式
策略模式:它定義了算法家族洋腮,分別封裝起來箫柳,讓他們之間可以相互替換,此模式讓算法的變化徐矩,不會影響到使用算法的客戶滞时。
>>> csuper = CashContext('正常收費')
>>> csuper.get_result(20)
20.0
>>> csuper = CashContext('滿300返100')
>>> csuper.get_result(300)
200.0
>>> csuper.get_result(200)
200.0
>>> csuper = CashContext('打八折')
>>> csuper.get_result(300)
240.0
策略模式就是用來封裝算法的,但是在實踐中滤灯,我們可以用它來封裝幾乎任何類型的規(guī)則坪稽,只要在分析過程中根據(jù)需要在不同時間應(yīng)用不同的業(yè)務(wù)規(guī)則,就可以考慮使用策略模式處理這種變化的可能性鳞骤。
裝飾模式
裝飾模式:動態(tài)地給一個對象添加一些額外的職責(zé)窒百,就增加功能來說,裝飾模式比生成子類更靈活豫尽。
裝飾模式的優(yōu)點就是把類中的裝飾功能從類中搬移去除篙梢,這樣可以簡化原有的類。有效地把類的核心職責(zé)和裝飾功能區(qū)分開了美旧,而且可以去除相關(guān)類中的重復(fù)的裝飾邏輯渤滞。
代理模式
為其他對象提供一種代理以控制對這個對象的訪問。
代碼示例:A追求C榴嗅,委托B送禮物給C妄呕。需求的重點是A和C不能直接接觸::
>>> jiaojiao = SchoolGirl()
>>> jiaojiao.name = '李嬌嬌'
工廠方法模式
工廠方法模式,定義一個用于創(chuàng)建對象的接口嗽测,讓子類決定實例化哪個類绪励。工廠方法使一個類的實例化延遲到其子類。
代碼示例:學(xué)習(xí)雷鋒好榜樣唠粥,繼承雷鋒精神的大學(xué)生和社區(qū)的構(gòu)建::
>>> factory = UndergraduateFactory()
>>> student = factory.create_leifeng()
>>> student.buyrice()
買米
>>> student.sweep()
掃地
>>> student.wash()
洗衣
工廠方法把簡單工廠的內(nèi)部邏輯判斷移到了客戶端代碼來進行疏魏。
原型模式
原型模式:用原型實例指定創(chuàng)建對象的種類,并且通過拷貝這些原型創(chuàng)建新的對象晤愧。其實就是從一個對象再創(chuàng)建另外一個可定制的對象大莫,并且不需要知道任何創(chuàng)建的細節(jié)::
>>> a = Resume('大鳥')
>>> a.set_personal_info('男', '29')
>>> a.set_work_experience('1998-2000', 'xx公司')
>>> b = a.clone()
>>> b.set_work_experience('2000-2006', 'xx企業(yè)')
>>> c = a.clone()
>>> c.set_personal_info('男', '24')
>>> a.display()
大鳥 男 29
工作經(jīng)歷: 1998-2000 xx公司
>>> b.display()
大鳥 男 29
工作經(jīng)歷: 2000-2006 xx企業(yè)
>>> c.display()
大鳥 男 24
工作經(jīng)歷: 1998-2000 xx公司
一般在初始化的信息不發(fā)生變化的情況下,克隆是最好的辦法官份,它既隱藏了對象的創(chuàng)建細節(jié)葵硕,又對性能是大大的提升眉抬。
模板方法模式
模板方法模式:定義一個操作中的算法的骨架,而將一些步驟延遲到子類中懈凹,模板方法是的子類可以不改變一個算法的結(jié)構(gòu)即可重新定義該算法的特定步驟::
>>> a = ConcreteClassA()
>>> a.template_method()
具體類A方法1實現(xiàn)
具體類A方法2實現(xiàn)
>>> b = ConcreteClassB()
>>> b.template_method()
具體類B方法1實現(xiàn)
具體類B方法2實現(xiàn)
外觀模式
外觀模式:為子系統(tǒng)中的一組接口提供一個一致的界面蜀变,此模式定義了一個高層接口,這個接口使得這一子系統(tǒng)更加容易使用::
>>> facade = Facade()
>>> facade.method_a()
--- 方法組A() ---
子系統(tǒng)方法一
子系統(tǒng)方法二
子系統(tǒng)方法四
>>> facade.method_b()
--- 方法組B() ---
子系統(tǒng)方法二
子系統(tǒng)方法三
外觀模式完美的體現(xiàn)了依賴倒轉(zhuǎn)原則和迪米特法則的思想介评,是常用的模式之一库北。經(jīng)典的三層架構(gòu),就需要考慮在層與層之間建立外觀Facade们陆。
建造者模式
建造者模式:將一個復(fù)雜對象的構(gòu)建與它的表示分離寒瓦,是的同樣的構(gòu)建過程,可以創(chuàng)建不同的表示::
>>> director = Director()
>>> b1 = ConcreateBuilder1()
>>> b2 = ConcreateBuilder2()
>>> director.construct(b1)
>>> p1 = b1.get_result()
>>> p1.show()
產(chǎn)品 創(chuàng)建 ----
部件A
部件B
>>> director.construct(b2)
>>> p2 = b2.get_result()
>>> p2.show()
產(chǎn)品 創(chuàng)建 ----
部件X
部件Y
建造者模式是當常見復(fù)雜對象的算法應(yīng)該獨立于該對象的組成部分以及它們的裝配方式時使用的模式坪仇。
如果我們用了建造者模式杂腰,那么用戶就只需指定需要建造的類型就可以得到他們,而具體建造的過程和細節(jié)就不需要知道了椅文。
觀察者模式
觀察者模式:定義了一種一對多的依賴關(guān)系喂很,讓多個觀察者對象同時監(jiān)聽某一個主體對象。這個主題對象在狀態(tài)發(fā)生變化時皆刺,會通知所有的觀察者對象少辣,讓它們能夠自動更新自己::
>>> s = ConcreteSubject()
>>> s.attach(ConcreteObserver(s, 'X'))
>>> s.attach(ConcreteObserver(s, 'Y'))
>>> s.attach(ConcreteObserver(s, 'Z'))
>>> s.subject_state = 'ABC'
>>> s.notify()
觀察者X的新狀態(tài)是ABC
觀察者Y的新狀態(tài)是ABC
觀察者Z的新狀態(tài)是ABC
當一個對象的改變需要同時改變其他對象的時候,且它不知道具體有多少對象有待改變時羡蛾,應(yīng)該考慮使用觀察者模式漓帅。
觀察者模式所做的工作其實就是解除耦合,讓耦合的雙方都依賴抽象痴怨,而不是依賴于具體忙干。從而使得各自的變化都不會影響另一邊的變化。是依賴倒轉(zhuǎn)原則的最佳體現(xiàn)浪藻。
但是抽象通知者還是依賴抽象觀察者豪直。在代碼中抽象觀察者中有一個update()方法,具體觀察者中都要實現(xiàn)該方法珠移,但是在實際中,可能有一些不一樣的操作末融,根本就不是同名的方法钧惧。這是不足的地方。
抽象工廠模式
抽象工廠方法:提供一個創(chuàng)建一系列相關(guān)或相互依賴對象的接口勾习,而無需指定它們具體的類::
>>> user = User()
>>> dept = Department()
>>> factory = SqlserverFactory()
>>> iu = factory.create_user()
>>> iu.insert(user)
在sql server 中給User表增加一條記錄
>>> iu.get_user(1)
在sql server 中根據(jù)ID得到User表一條記錄
>>> factory = AccessFactory()
>>> id = factory.create_department()
>>> id.insert(dept)
在Access中給Department表增加一條記錄
>>> id.get_dept(1)
在Access中根據(jù)ID得到Department表一條記錄
>>> iu = factory.create_user()
>>> iu.insert(user)
在Access中給User表增加一條記錄
>>> iu.get_user(1)
在Access中根據(jù)Id得到User表一條記錄
抽象工廠模式的優(yōu)點:
- 1浓瞪、易于交換產(chǎn)品系列,由于具體工廠類巧婶,在一個應(yīng)用中只需要在初始化的時候出現(xiàn)一次乾颁,這就使得改變一個應(yīng)用的具體工廠變得非常容易涂乌,它只需要改變具體工廠即可使用不 同
的產(chǎn)品配置。 - 2英岭、讓具體的創(chuàng)建實例過程和客戶端分離湾盒,客戶端是通過它們的抽象接口操作實例,產(chǎn)品的具體類名也被具體工廠的實現(xiàn)分離诅妹,不會出現(xiàn)在客戶代碼中罚勾。
缺點:
新增或修改時,可能需要大量的改動吭狡。
狀態(tài)模式
狀態(tài)模式:當一個對象的內(nèi)在狀態(tài)改變時尖殃,允許改變其行為,這個對象看起來像是一個改變了其類::
>>> c = Context(ConcreteStateA())
>>> c.request()
當前狀態(tài):stateB
>>> c.request()
當前狀態(tài):stateA
>>> c.request()
當前狀態(tài):stateB
>>> c.request()
當前狀態(tài):stateA
>>> c.request()
當前狀態(tài):stateB
狀態(tài)模式主要解決的是當控制一個對象狀態(tài)轉(zhuǎn)換的條件表達式過于復(fù)雜時的情況划煮,把狀態(tài)的判斷轉(zhuǎn)移到表示不同狀態(tài)的一系列類中可以把復(fù)雜的判斷邏輯簡化送丰。
狀態(tài)模式的好處是將與特定狀態(tài)相關(guān)的行為局部化,并且將不同狀態(tài)的行為分割開來弛秋。
適配器模式
適配器模式:將一個類的接口轉(zhuǎn)換成客戶希望的另外一個接口器躏。使得原本由于接口不兼容而不能一起工作的那些類可以一起工作::
>>> target = Adapter()
>>> target.request()
特殊請求
備忘錄模式
備忘錄模式:在不破壞封裝性的前提下,捕獲一個對象的內(nèi)部狀態(tài)铐懊,并在該對象之外保存這個狀態(tài)邀桑。這樣就可以將該對象恢復(fù)到原先保存的狀態(tài)::
>>> o = Originator()
>>> o.state = 'ON' # 初始狀態(tài)
>>> o.show()
state= ON
>>> caretaker = Caretaker()
>>> caretaker.memento = o.create_memento()
>>> o.state = 'OFF' # 改變狀態(tài)
>>> o.show()
state= OFF
>>> o.set_memento(caretaker.memento) # 恢復(fù)
>>> o.show()
state= ON
缺點:當需要備忘的對象狀態(tài)數(shù)據(jù)很大很多時,那么在資源消耗上科乎,備忘錄對象會非常消耗資源壁畸。
組合模式
組合模式:將對象組合成樹形結(jié)構(gòu)以表示部分整體的層次結(jié)構(gòu),組合模式使得用戶對單個對象和組合對象的使用具有一致性::
>>> root = Composite('root')
>>> root.add(Leaf('Leaf A'))
>>> root.add(Leaf('Leaf B'))
>>> comp = Composite('Composite X')
>>> comp.add(Leaf('Leaf A'))
>>> comp.add(Leaf('Leaf B'))
>>> root.add(comp)
>>> comp2 = Composite('Composite XY')
>>> comp2.add(Leaf('Leaf A'))
>>> comp2.add(Leaf('Leaf B'))
>>> comp.add(comp2)
>>> root.display(1)
- root
-- Leaf A
-- Leaf B
-- Composite X
--- Leaf A
--- Leaf B
--- Composite XY
---- Leaf A
---- Leaf B
組合模式定義了包含基本對象和組合對象的類層次結(jié)構(gòu)茅茂,基本對象可以被組合成更復(fù)雜的組合對象捏萍,而這個組合對象又可以被組合這樣不斷地遞歸下去。
迭代器模式
迭代器模式:提供一種方法順序訪問一個聚合對象中各個元素空闲,而不是暴露該對象的內(nèi)部表示令杈。代碼事例為乘務(wù)員迭代檢票的模擬演示::
>>> a = ConcreteAggregate()
>>> a[0] = '大鳥'
>>> a[1] = '小菜'
>>> a[2] = '行李'
>>> a[3] = '老外'
>>> a[4] = '員工'
>>> a[5] = '小偷'
>>> i = ConcreteIterator(a)
>>> item = i.first()
>>> while not i.is_done():
... print('{} 請買票!'.format(i.current_item()))
... i.next()
大鳥 請買票!
小菜 請買票!
行李 請買票!
老外 請買票!
員工 請買票!
小偷 請買票!
為遍歷不同的聚合結(jié)構(gòu)提供如開始、下一個碴倾、是否結(jié)束逗噩、當前哪一項等統(tǒng)一的接口。現(xiàn)在高級編程語言如C#跌榔、JAVA异雁、Python等本身已經(jīng)把這個模式做在語言中。
單例模式
單例模式:保證一個類僅有一個實例僧须,并提供一個訪問它的全局訪問點::
>>> singleton1 = Singleton('wen') # doctest: +ELLIPSIS
單例:...
>>> singleton2 = Singleton('wen1') # doctest: +ELLIPSIS
單例:...
>>> print(singleton1 is singleton2)
True
通常我們可以讓一個全局變量使得一個對象被訪問纲刀,但是它不能防止你實例化多個對象,一個最好的辦法就是:讓類自身負責(zé)它的唯一實例担平。這個類可以保證沒有其他的實例可以被創(chuàng)建示绊,并且它可以提供一個訪問該實例的方法锭部。
橋接模式
橋接模式:將抽象部分與它的實現(xiàn)部分分離,使他們都可以獨立的變化::
>>> ab = RefinedAbstraction()
>>> ab.implementor = ConcreteImplementorA()
>>> ab.operation()
具體實現(xiàn)A的方法執(zhí)行面褐。
>>> ab.implementor = ConcreteImplementorB()
>>> ab.operation()
具體實現(xiàn)B的方法執(zhí)行拌禾。
命令模式
命令模式:將一個請求封裝為一個對象,從而使你可用不同的請求對客戶進行參數(shù)化盆耽;對請求排隊或記錄請求日志蹋砚,以及支持可撤銷的操作。
>>> r = Receiver()
>>> c = ConcreteCommand(r)
>>> i = Invoker()
>>> i.command = c
>>> i.execute_command()
執(zhí)行請求摄杂!
命令模式的優(yōu)點:
- 1 能較容易的設(shè)計一個命令隊列
- 2 在需要的情況下坝咐,可以較容易的將命令記入日志
- 3 允許接收請求的一方?jīng)Q定是否要否決請求
- 4 可以容易的實現(xiàn)對請求的撤銷和重做
- 5 由于加新的具體命令類不影響其他的類,因此增加新的具體命令類很容易
- 6 命令模式把請求一個操作的對象與知道怎么執(zhí)行一個操作的對象分割開析恢。
職責(zé)鏈模式
職責(zé)鏈模式:使多個對象都有機會處理請求墨坚,從而避免請求的發(fā)送者和接收者之間的耦合關(guān)系。將這個對象連成一條鏈映挂,并沿著這條鏈傳遞該請求泽篮,直到有一個對象處理它為止。
>>> h1 = ConcreteHandler1()
>>> h2 = ConcreteHandler2()
>>> h3 = ConcreteHandler3()
>>> h1.successor = h2 # 設(shè)置職責(zé)鏈上家和下家
>>> h2.successor = h3
>>> requests = [2, 5, 14, 22, 18, 3, 27, 20]
>>> for request in requests:
... h1.handle_request(request)
ConcreteHandler1 處理請求 2
ConcreteHandler1 處理請求 5
ConcreteHandler2 處理請求 14
ConcreteHandler3 處理請求 22
ConcreteHandler2 處理請求 18
ConcreteHandler1 處理請求 3
ConcreteHandler3 處理請求 27
ConcreteHandler3 處理請求 20
需要注意的地方柑船,一個請求極有可能到了鏈的末端都得不到處理帽撑,或者因為沒有正確配置而得不到處理。
中介者模式
中介者模式:用一個中介對象來封裝一系列的對象交互鞍时。中介者使各對象不需要顯式的相互引用亏拉,從而使其耦合松散,而且可以獨立地改變它們之間的交互::
>>> m = ConcreteMediator()
>>> c1 = ConcreteHandler1(m)
>>> c2 = ConcreteHandler2(m)
>>> m.colleague1 = c1
>>> m.colleague2 = c2
>>> c1.send('吃飯了嗎逆巍?')
同事2得到消息: 吃飯了嗎及塘?
>>> c2.send('沒有呢,你打算請客锐极?')
同事1得到消息: 沒有呢笙僚,你打算請客?
享元模式
享元模式:運用共享技術(shù)有效地支持大量細粒度的對象::
>>> extrinsicstate = 22
>>> f = FlyweightFactory()
>>> fx = f.get_flyweight('X')
>>> fx.operation(extrinsicstate - 1)
具體Flyweight: 21
>>> fy = f.get_flyweight('Y')
>>> fy.operation(extrinsicstate - 2)
具體Flyweight: 20
>>> uf = UnsharedConcreteFlyweight()
>>> uf.operation(extrinsicstate - 3)
不共享的具體Flyweight: 19
享元模式可以避免大量非常相似類的開銷灵再。在程序設(shè)計中肋层,有時需要生成大量的細粒度的類示例來表示數(shù)據(jù),如果能夠發(fā)現(xiàn)這些實例除了幾個參數(shù)外基本上都相同的翎迁,有時就能夠受大幅度的減少需要實例化的類數(shù)量栋猖。如果把這些參數(shù)移到類實例的外面,在方法調(diào)用的時候?qū)⑺鼈儌鬟f進來鸳兽,就可以通過共享大幅度的減少單個實例的數(shù)目。
應(yīng)用場合:如果一個應(yīng)用程序使用了大量的對象罕拂,而大量的這些對象造成了很大的存儲開銷時揍异,應(yīng)該考慮使用全陨,還有就是對象的大多數(shù)狀態(tài)可以外部狀態(tài),如果刪除對象的外部狀態(tài)衷掷,那么可以用相對較少的共享對象取代很多的組對象辱姨,此時可以考慮使用享元模式。
解釋器模式
解釋器模式:給定一個語言戚嗅,定義它的文法的一種表示雨涛,并定義一個解釋器,這個解釋器使用該表示來解釋語言中的句子::
>>> context = Context()
>>> ll = []
>>> ll.append(TerminalExpression())
>>> ll.append(TerminalExpression())
>>> ll.append(NonterminalExpression())
>>> ll.append(TerminalExpression())
>>> for exp in ll:
... exp.interpret(context)
終端解釋器
終端解釋器
非終端解釋器
終端解釋器
比如懦胞,在字符串搜索匹配的字符或判斷一個字符串是否符合我們規(guī)定的格式替久,我們會用到的正則表達式技術(shù),就是該模式的很好應(yīng)用躏尉。
優(yōu)點:容易的改變和擴展文法蚯根,因為該模式使用類來表示文法規(guī)則,你可使用繼承來改變或擴展該方法胀糜。也比較容易實現(xiàn)文法颅拦,因為定義抽象語法樹中各個節(jié)點的類的實現(xiàn)大體類似,這些類都易于直接編寫教藻。
缺點:該模式為文法中的每一條規(guī)則至少定義了一個類距帅,因此包含許多規(guī)則的文法就很難管理和維護。建議當文法非常復(fù)雜時括堤,使用其他的技術(shù)如語法分析程序或編譯器生成器來處理碌秸。
訪問者模式
訪問者模式:表示一個作用于某對象結(jié)構(gòu)中各元素的操作。它使你可以在不改變各元素的類的前提下定義于這些元素的新操作::
>>> o = ObjectStructure()
>>> o.attach(ConcreteElementA())
>>> o.attach(ConcreteElementB())
>>> v1 = ConcreteVisitor1()
>>> v2 = ConcreteVisitor2()
>>> o.accept(v1)
ConcreteElementA被ConcreteVisitor1訪問
ConcreteElementB被ConcreteVisitor1訪問
>>> o.accept(v2)
ConcreteElementA被ConcreteVisitor2訪問
ConcreteElementB被ConcreteVisitor2訪問
訪問者模式適用于數(shù)據(jù)結(jié)構(gòu)相對穩(wěn)定的系統(tǒng)痊臭,它把數(shù)據(jù)結(jié)構(gòu)作用于結(jié)構(gòu)上的操作之間的耦合解脫開哮肚,使得操作集合可以相對自由地演化。
如果系統(tǒng)有比較穩(wěn)定的數(shù)據(jù)結(jié)構(gòu)又有易于變化的算法的話广匙,使用訪問者模式是比較合適的因為該模式使得算法操作的增加變得容易允趟。
缺點:就是使增加新的數(shù)據(jù)結(jié)構(gòu)變得困難了。該模式較為復(fù)雜鸦致。當你真正需要它的時候潮剪,才考慮使用它。