訪問者模式Visitor
背景
1.概述
- 在軟件開發過程中,對于系統中的某些對象,它們存儲在同一個集合collection中,且具有不同的類型,而且對于該集合中的對象,可以接受一類稱為訪問者的對象來訪問,而且不同的訪問者其訪問方式有所不同
2.問題
- 對同一集合對象的操作并不是唯一的,對相同的元素對象可能存在多種不同的操作方式。而且這些操作方式并不穩定,如果對需要增加新的操作,如何滿足新的業務需求?
3.解決方案
訪問者模式:表示一個作用于某對象結構中的各元素的操作。它使你可以在不改變各元素的類的前提下定義作用于這些元素的新操作。
1)訪問者模式中對象結構存儲了不同類型的元素對象,以供不同訪問者訪問。
2)訪問者模式包括兩個層次結構,一個是訪問者層次結構,提供了抽象訪問者和具體訪問者,一個是元素層次結構,提供了抽象元素和具體元素。
相同的訪問者可以不同的方式訪問不同的元素,相同的元素可以接受不同訪問者以不同訪問方式訪問。在訪問者模式中,增加新的訪問者無須修改原有系統,系統具有較好的可擴展性
剖析
定義
- 表示一個作用于某個對象結構中各元素的操作。它使你可以再不改變各元素的類的前提下定義這些元素的新操作。
- 1)訪問者模式中對象結構存儲了不同類型的元素對象,以供不同訪問者訪問。
- 2)訪問者模式包括兩個層次結構,一個是訪問者層次結構,提供了抽象訪問者和具體訪問者,一個是元素層次結構,提供了抽象元素和具體元素。
相同的訪問者可以以不同的方式訪問不同的元素,相同的元素可以接受不同訪問者以不同訪問方式訪問。在訪問者模式中,增加新的訪問者無須修改原有系統,系統具有較好的可擴展性
本質
- 預留通路,回調實現
UML
Visitor-UML.png
模式組成
- 抽象訪問者(Vistor): — 為該對象結構中ConcreteElement的每一個類聲明一個Visit操作。該操作的名字和特
- 征標識了發送Visit請求給該訪問者的那個類。這使得訪問者可以確定正被訪問元素
- 的具體的類。這樣訪問者就可以通過該元素的特定接口直接訪問它。
- 具體訪問者(ConcreteVisitor): — 實現每個由Visitor聲明的操作。每個操作實現本算法的一部分,而該算法片斷乃是
- 對應于結構中對象的類。ConcreteVisitor為該算法提供了上下文并存儲它的局部狀態。
- 這一狀態常常在遍歷該結構的過程中累積結果。
- 抽象元素(Element):定義一個Accept操作,它以一個訪問者為參數。
- 具體元素(ConcreteElement): 實現Accept操作,該操作以一個訪問者為參數。
- 對象結構(ObjectStructure): 能枚舉它的元素。可以提供一個高層的接口以允許該訪問者訪問它的元素。可以是一個復合或是一個集合,如一個列表或一個無序集合。
何時使用
- 一個復雜的對象結構包含很多其他對象,他們有不同的接口,但是想對這些對象實施一些依賴于具體類型的操作。
- 需要對一個組合結構中的對具體對象進行很多不相關的操作,但是不想比這些對象“污染”這些對象的類,可以將相關的操作集中起來,定義一個訪問者類中,并在需要在訪問者中定義的操作時使用它。
- 定義復雜的類很少做修改,但經常需要向其添加新的操作。
優缺點
優點:
- ?使得增加新的訪問操作變得很容易。如果一些操作依賴于一個復雜的結構對象的話,那么一般而言,增加新的操作會很復雜。而使用訪問者模式,增加新的操作就意味著增加一個新的訪問者類,因此,變得很容易。
- ?將有關元素對象的訪問行為集中到一個訪問者對象中,而不是分散到一個個的元素類中。
- ?訪問者模式可以跨過幾個類的等級結構訪問屬于不同的等級結構的成員類。迭代子只能訪問屬于同一個類型等級結構的成員對象,而不能訪問屬于不同等級結構的對象。訪問者模式可以做到這一點。
- ?讓用戶能夠在不修改現有類層次結構的情況下,定義該類層次結構的操作。
- 好的擴展性 復用性 ;分離無關行為,
缺點:
- ?增加新的元素類很困難。在訪問者模式中,每增加一個新的元素類都意味著要在抽象訪問者角色中增加一個新的抽象操作,并在每一個具體訪問者類中增加相應的具體操作,違背了“開閉原則”的要求。
- ?破壞封裝。訪問者模式要求訪問者對象訪問并調用每一個元素對象的操作,這意味著元素對象有時候必須暴露一些自己的內部操作和內部狀態,否則無法供訪問者訪問。
- 對象結構變化困難,破壞了封裝
- 具體元素對訪問者公布細節
- 具體元素變更比較困難
- 違背了依賴倒轉原則
總結
相關模式
- ?迭代器模式:由于訪問者模式需要對對象結構進行操作,而對象結構本身是一個元素對象的集合,因此訪問者模式經常需要與迭代器模式聯用,在對象結構中使用迭代器來遍歷元素對象。
- ?組合模式:在訪問者模式中,元素對象可能存在容器對象和葉子對象,因此可以結合組合模式來進行設計。
擴展
傾斜的“開閉原則”
?訪問者模式以一種傾斜的方式支持“開閉原則”,增加新的訪問者方便,但是增加新的元素很困難。
面向對象的設計原則中最重要的便是所謂的"開一閉"原則。一個軟件系統的設計應當盡量做到對擴展開放,對修改關閉。達到這個原則的途徑就是遵循"對變化的封裝"的原則。這個原則講的是在進行軟件系統的設計時,應當設法找出一個軟件系統中會變化的部分,將之封裝起來。
很多系統可以按照算法和數據結構分開,也就是說一些對象含有算法,而另一些對象含有數據,接受算法的操作。如果這樣的系統有比較穩定的數據結構,又有易于變化的算法的話,使用訪問者模式就是比較合適的,因為訪問者模式使得算法操作的增加變得容易。
反過來,如果這樣一個系統的數據結構對象易于變化,經常要有新的數據對象增加進來的話,就不適合使用訪問者模式。因為在訪問者模式中增加新的節點很困難,要涉及到在抽象訪問者和所有的具體訪問者中增加新的方法。
總之,訪問者模式能給一系列對象透明地添加功能,從而避免在維護期間對一系列對象進行修改,而且還能變相實現復用訪問者所具有的功能