訪問者模式Visitor
背景
1.概述
- 在軟件開發(fā)過程中,對(duì)于系統(tǒng)中的某些對(duì)象,它們存儲(chǔ)在同一個(gè)集合collection中涉馁,且具有不同的類型,而且對(duì)于該集合中的對(duì)象爱致,可以接受一類稱為訪問者的對(duì)象來訪問烤送,而且不同的訪問者其訪問方式有所不同
2.問題
- 對(duì)同一集合對(duì)象的操作并不是唯一的,對(duì)相同的元素對(duì)象可能存在多種不同的操作方式糠悯。而且這些操作方式并不穩(wěn)定帮坚,如果對(duì)需要增加新的操作妻往,如何滿足新的業(yè)務(wù)需求?
3.解決方案
訪問者模式:表示一個(gè)作用于某對(duì)象結(jié)構(gòu)中的各元素的操作试和。它使你可以在不改變各元素的類的前提下定義作用于這些元素的新操作讯泣。
1)訪問者模式中對(duì)象結(jié)構(gòu)存儲(chǔ)了不同類型的元素對(duì)象,以供不同訪問者訪問阅悍。
2)訪問者模式包括兩個(gè)層次結(jié)構(gòu)好渠,一個(gè)是訪問者層次結(jié)構(gòu),提供了抽象訪問者和具體訪問者节视,一個(gè)是元素層次結(jié)構(gòu)拳锚,提供了抽象元素和具體元素。
相同的訪問者可以不同的方式訪問不同的元素寻行,相同的元素可以接受不同訪問者以不同訪問方式訪問霍掺。在訪問者模式中,增加新的訪問者無須修改原有系統(tǒng)拌蜘,系統(tǒng)具有較好的可擴(kuò)展性
剖析
定義
- 表示一個(gè)作用于某個(gè)對(duì)象結(jié)構(gòu)中各元素的操作杆烁。它使你可以再不改變各元素的類的前提下定義這些元素的新操作。
- 1)訪問者模式中對(duì)象結(jié)構(gòu)存儲(chǔ)了不同類型的元素對(duì)象简卧,以供不同訪問者訪問兔魂。
- 2)訪問者模式包括兩個(gè)層次結(jié)構(gòu),一個(gè)是訪問者層次結(jié)構(gòu)贞滨,提供了抽象訪問者和具體訪問者入热,一個(gè)是元素層次結(jié)構(gòu),提供了抽象元素和具體元素晓铆。
相同的訪問者可以以不同的方式訪問不同的元素勺良,相同的元素可以接受不同訪問者以不同訪問方式訪問。在訪問者模式中骄噪,增加新的訪問者無須修改原有系統(tǒng)尚困,系統(tǒng)具有較好的可擴(kuò)展性
本質(zhì)
- 預(yù)留通路,回調(diào)實(shí)現(xiàn)
UML
模式組成
- 抽象訪問者(Vistor): — 為該對(duì)象結(jié)構(gòu)中ConcreteElement的每一個(gè)類聲明一個(gè)Visit操作链蕊。該操作的名字和特
- 征標(biāo)識(shí)了發(fā)送Visit請(qǐng)求給該訪問者的那個(gè)類事甜。這使得訪問者可以確定正被訪問元素
- 的具體的類。這樣訪問者就可以通過該元素的特定接口直接訪問它滔韵。
- 具體訪問者(ConcreteVisitor): — 實(shí)現(xiàn)每個(gè)由Visitor聲明的操作逻谦。每個(gè)操作實(shí)現(xiàn)本算法的一部分,而該算法片斷乃是
- 對(duì)應(yīng)于結(jié)構(gòu)中對(duì)象的類陪蜻。ConcreteVisitor為該算法提供了上下文并存儲(chǔ)它的局部狀態(tài)邦马。
- 這一狀態(tài)常常在遍歷該結(jié)構(gòu)的過程中累積結(jié)果。
- 抽象元素(Element):定義一個(gè)Accept操作,它以一個(gè)訪問者為參數(shù)滋将。
- 具體元素(ConcreteElement): 實(shí)現(xiàn)Accept操作邻悬,該操作以一個(gè)訪問者為參數(shù)。
- 對(duì)象結(jié)構(gòu)(ObjectStructure): 能枚舉它的元素随闽「阜幔可以提供一個(gè)高層的接口以允許該訪問者訪問它的元素【蛳埽可以是一個(gè)復(fù)合或是一個(gè)集合蛾扇,如一個(gè)列表或一個(gè)無序集合。
何時(shí)使用
- 一個(gè)復(fù)雜的對(duì)象結(jié)構(gòu)包含很多其他對(duì)象魏滚,他們有不同的接口屁桑,但是想對(duì)這些對(duì)象實(shí)施一些依賴于具體類型的操作。
- 需要對(duì)一個(gè)組合結(jié)構(gòu)中的對(duì)具體對(duì)象進(jìn)行很多不相關(guān)的操作栏赴,但是不想比這些對(duì)象“污染”這些對(duì)象的類,可以將相關(guān)的操作集中起來靖秩,定義一個(gè)訪問者類中须眷,并在需要在訪問者中定義的操作時(shí)使用它。
- 定義復(fù)雜的類很少做修改沟突,但經(jīng)常需要向其添加新的操作花颗。
優(yōu)缺點(diǎn)
優(yōu)點(diǎn):
- ?使得增加新的訪問操作變得很容易。如果一些操作依賴于一個(gè)復(fù)雜的結(jié)構(gòu)對(duì)象的話惠拭,那么一般而言扩劝,增加新的操作會(huì)很復(fù)雜。而使用訪問者模式职辅,增加新的操作就意味著增加一個(gè)新的訪問者類棒呛,因此,變得很容易域携。
- ?將有關(guān)元素對(duì)象的訪問行為集中到一個(gè)訪問者對(duì)象中簇秒,而不是分散到一個(gè)個(gè)的元素類中。
- ?訪問者模式可以跨過幾個(gè)類的等級(jí)結(jié)構(gòu)訪問屬于不同的等級(jí)結(jié)構(gòu)的成員類秀鞭。迭代子只能訪問屬于同一個(gè)類型等級(jí)結(jié)構(gòu)的成員對(duì)象趋观,而不能訪問屬于不同等級(jí)結(jié)構(gòu)的對(duì)象。訪問者模式可以做到這一點(diǎn)锋边。
- ?讓用戶能夠在不修改現(xiàn)有類層次結(jié)構(gòu)的情況下皱坛,定義該類層次結(jié)構(gòu)的操作。
- 好的擴(kuò)展性 復(fù)用性 豆巨;分離無關(guān)行為剩辟,
缺點(diǎn):
- ?增加新的元素類很困難。在訪問者模式中,每增加一個(gè)新的元素類都意味著要在抽象訪問者角色中增加一個(gè)新的抽象操作抹沪,并在每一個(gè)具體訪問者類中增加相應(yīng)的具體操作刻肄,違背了“開閉原則”的要求。
- ?破壞封裝融欧。訪問者模式要求訪問者對(duì)象訪問并調(diào)用每一個(gè)元素對(duì)象的操作敏弃,這意味著元素對(duì)象有時(shí)候必須暴露一些自己的內(nèi)部操作和內(nèi)部狀態(tài),否則無法供訪問者訪問噪馏。
- 對(duì)象結(jié)構(gòu)變化困難麦到,破壞了封裝
- 具體元素對(duì)訪問者公布細(xì)節(jié)
- 具體元素變更比較困難
- 違背了依賴倒轉(zhuǎn)原則
總結(jié)
相關(guān)模式
- ?迭代器模式:由于訪問者模式需要對(duì)對(duì)象結(jié)構(gòu)進(jìn)行操作,而對(duì)象結(jié)構(gòu)本身是一個(gè)元素對(duì)象的集合欠肾,因此訪問者模式經(jīng)常需要與迭代器模式聯(lián)用瓶颠,在對(duì)象結(jié)構(gòu)中使用迭代器來遍歷元素對(duì)象。
- ?組合模式:在訪問者模式中刺桃,元素對(duì)象可能存在容器對(duì)象和葉子對(duì)象粹淋,因此可以結(jié)合組合模式來進(jìn)行設(shè)計(jì)。
擴(kuò)展
傾斜的“開閉原則”
?訪問者模式以一種傾斜的方式支持“開閉原則”瑟慈,增加新的訪問者方便桃移,但是增加新的元素很困難。
面向?qū)ο蟮脑O(shè)計(jì)原則中最重要的便是所謂的"開一閉"原則葛碧。一個(gè)軟件系統(tǒng)的設(shè)計(jì)應(yīng)當(dāng)盡量做到對(duì)擴(kuò)展開放借杰,對(duì)修改關(guān)閉。達(dá)到這個(gè)原則的途徑就是遵循"對(duì)變化的封裝"的原則进泼。這個(gè)原則講的是在進(jìn)行軟件系統(tǒng)的設(shè)計(jì)時(shí)蔗衡,應(yīng)當(dāng)設(shè)法找出一個(gè)軟件系統(tǒng)中會(huì)變化的部分,將之封裝起來乳绕。
很多系統(tǒng)可以按照算法和數(shù)據(jù)結(jié)構(gòu)分開绞惦,也就是說一些對(duì)象含有算法,而另一些對(duì)象含有數(shù)據(jù)刷袍,接受算法的操作翩隧。如果這樣的系統(tǒng)有比較穩(wěn)定的數(shù)據(jù)結(jié)構(gòu),又有易于變化的算法的話呻纹,使用訪問者模式就是比較合適的堆生,因?yàn)樵L問者模式使得算法操作的增加變得容易。
反過來雷酪,如果這樣一個(gè)系統(tǒng)的數(shù)據(jù)結(jié)構(gòu)對(duì)象易于變化淑仆,經(jīng)常要有新的數(shù)據(jù)對(duì)象增加進(jìn)來的話,就不適合使用訪問者模式哥力。因?yàn)樵谠L問者模式中增加新的節(jié)點(diǎn)很困難蔗怠,要涉及到在抽象訪問者和所有的具體訪問者中增加新的方法墩弯。
總之,訪問者模式能給一系列對(duì)象透明地添加功能寞射,從而避免在維護(hù)期間對(duì)一系列對(duì)象進(jìn)行修改渔工,而且還能變相實(shí)現(xiàn)復(fù)用訪問者所具有的功能