訪問者模式

2021-05-21 13:04:37 字數 3801 閱讀 3928

行為模式中的訪問者模式

訪問者模式是物件的行為模式。訪問者模式的目的是封裝一些施加於某種資料結構元素之上的操作,一旦這些操作需要修改的話,接受這個操作的資料結構則可以保持不變。

動機:類層次結構中可能經常由於引入新的操作,從而將型別變得脆弱。。。在軟體構建過程中,由於需求的改變,某些類層次結構中常常需要增加新的行為(方法

),如果直接在基類中做這樣的更改,將會給子類帶來很繁重的變更負擔,甚至破壞原有的設計。

如何在不更改類層次結構的前提下,在執行時根據需要透明地位層次結構上的各個類動態新增新的操作,從而避免上述問題?

意圖(intent

)表示乙個作用於某物件結構中的各元素的操作,它可以在不改變各元素的類的前提下定義作用於這些元素的新的操作。

雙重分發:

所謂雙重分發即

visitor

模式中間包括了兩個多型分發

(注意其中的多型機制

):第乙個為

accept()

方法的多型辨析;第二個

visit

方法的多型辨析。

問題:聚集是大多數系統都要處理的一種容器物件。它儲存了對其它物件的引用。相信大家都有處理聚集的經驗,但是大家處理過的大多數聚集恐怕都是同類物件的聚集。換言之,在聚集上採取的操作都是一些針對同型別物件的同類操作,而迭代子模式就是為這種情況準備的設計模式。

下面就是這樣的乙個例子,如**清單

1所示。

publicvoidprint(collection collection)

} 那麼乙個很多人都沒有考慮過的問題就是,如何針對乙個儲存有不同型別物件的聚集採取某種操作呢?

粗看上來,這並不是什麼難題,仍然以上面的

print()

方法為例,如果

collection

聚集中的元素有可能還是聚集,那麼呼叫聚集的

tostring

就沒有意義,應該呼叫它的內部元素的

tostring()

方法。換言之,上面的方法就應當改寫成下面的這樣,如下**:

publicvoidprint(collection collection)else}

} 但是這還沒有完,如果這個操作對不同型別的元素有所不同時怎麼辦呢?比如系統可能會要求在列印字串時,加上單引號;在列印

double

型別的資料時,在資料後面加上

」d」;在列印

float

型別的資料時,在資料後面加上「

f」。這時,直截了當的答案就是繼續修改上面的

print()

方法,如**清單:

publicvoidprint(collection collection)elseif(oinstanceofstring)elseif(oinstanceofdouble)elseif(oinstanceoffloat)else}

} 這個條件轉移語句變得越來越長,**也越來越難以維護。換言之,如果需要針對乙個包含不同型別元素的聚集採取某種操作,而操作的細節根據元素的型別不同而有所不同時,就會出現必須對元素型別判斷的條件轉移語句。這就是雙重分派的實際應用。

這個時候,使用訪問者模式就是乙個值得考慮的解決方案。

訪問者模式

訪問者模式適用於資料結構相對未定的系統,它把資料結構和作用於結構上的操作之間的耦合解脫開,使得操作集合可以相對自由地演化。訪問者模式的簡略圖如下圖所示。

資料結構的每乙個節點都可以接受乙個訪問者呼叫,此節點向訪問者物件傳入節點物件,而訪問者物件則返回過來執行節點物件的操作,這樣的過程叫做「雙重分派」。節點呼叫訪問者,將它自己傳入,訪問者則將某演算法針對此節點執行。

雙重分派意味著是施加於節點之上的操作是基於訪問者和節點本身的資料型別,而不僅僅是其中的一者。

訪問者模式的結構

如下圖所示,這個靜態圖顯示了有兩個具體訪問者和兩個具體節點的訪問者模式的設計,必須指出的是,具體訪問者的數目與具體節點的數目沒有任何關係,雖然在這個示意圖性的系統裡面兩者的數目都是兩個。

訪問者模式所涉及的角色:

訪問者模式涉及到抽象訪問者角色,具體訪問者角色,抽象節點角色,具體節點角色,結構物件角色以及客戶端角色。 ◆

抽象訪問者

(vistor)

角色:說明了乙個或者多個訪問操作,形成所有的具體元素角色必須實現的介面。 ◆

具體訪問者

(concretevisitor)

角色:實現抽象訪問者角色所宣告的介面,也就是抽象訪問者所宣告的各個訪問操作。 ◆

抽象節點

(node)

角色:宣告乙個接受操作,接受乙個訪問者物件作為乙個參量。 ◆

具體節點(

node

)角色:實現了抽象元素所規定的接受操作。 ◆

結構物件

(objectstructure)

角色:有如下的一些責任,可以遍歷結構中的所有的元素;如果需要,提供乙個高層次的介面讓訪問者物件可以訪問每乙個元素;如需要,可以設計成乙個復合物件或者乙個聚合,如列

(list)

或集合(

set)

在實際系統中訪問者模式通常是用來處理複雜的物件樹結構的,而且訪問者模式可以用來處理跨越多個等級結構的樹結構的問題。這正是訪問者模式的功能強大之處。

什麼情況下應當使用訪問者模式

訪問模式僅應當在為訪問的類結構非常穩定的情況下使用。換言之系統很少出現需要信節點的情況。如果出現需要加入新節點的情況怎麼辦呢?那是舊必須在每乙個訪問物件裡加入乙個對應於這個新節點的訪問操作,而這時乙個系統的大規模修改,因而是違背「開

-閉」原則的。

訪問者模式允許在節點中加入新的方法,相應的僅僅需要在乙個新的訪問者類中加入此方法,而不需要在每乙個訪問者類中都加入此方法。

顯然,訪問者模式提供了傾斜的可擴充套件性:方法集合的可擴充套件性和類集合的不可擴充套件性。

換言之,如果系統的資料結構時頻繁變化的,則不適合使用訪問者模式。 「開

-閉」原則和對變化的封裝

物件導向的設計原則中最重要的原則便是所謂的「開

-閉」原則。乙個軟體系統的設計應當盡量做到對擴充套件開放,對修改關閉,達到這個原則的途徑的就是遵循「對變化的封裝」的原則,這個原則講的是在進行軟體系統的設計時,應當設法找到乙個軟體系統中會變化的部分,將之封裝起來。

很多系統可以按照演算法和資料結構分開,也就是說一些物件含有演算法,而另一些物件含有資料,接受演算法的操作,如果這樣的系統有比較穩定的資料結構,又有易於變化的演算法的話,使用訪問者模式就是比較合適的,因為訪問者模式使得演算法操作的增加變得容易。

使用訪問者模式的優缺點:

訪問者模式使得增加新的操作更容易,如果一些操作依賴乙個複雜的結構物件的話,那麼一般而言,增加新的操作會很複雜,而使用訪問者模式,增加新的操作就意味著增加乙個新的訪問者類,因此變得更容易。

訪問者模式將有關的行為集中到乙個訪問者物件中,而不是分散到乙個個的節點類中。

訪問者模式可以跨過幾個類的等級結構訪問屬於不同的等級結構的成員類。迭代子只能訪問屬於同乙個型別等級結構的成員物件,而不能訪問屬於不同等級結構的物件,訪問者模式可以做到這一點。

積累狀態。每乙個單獨的訪問者物件都集中了相關的行為,從而也就可以在訪問過程中將執行的操作的狀態積累在自己內部,而不是分散到很多的節點物件中,這是有益於系統維護的優點。

訪問者模式

訪問者模式 visitor pattern 訪問者模式是物件的行為模式。訪問者模式的目的是封裝一些施加於某種資料結構元素之上的操作。一旦這些操作需要修改的話,接受這個操作的資料結構則可以保持不變。一 問題 集合是大多數的系統都要處理的一種容器物件,它儲存了對其它物件的引用。一般情況下,在集合上採取的...

訪問者模式

1.說明 namespace visitorspattern 象棋類 public abstract class chess public class redchess chess public class blackchess chess 在贏的情況下的狀態 public class win ac...

訪問者模式

1.意圖 資料結構和對資料結構操作的解耦。特點 資料結構是穩定的,操作是變化的。2 角色 1 抽象訪問者 宣告對所有元素訪問的介面 2 具體訪問者 3 抽象節點 宣告接收訪問者 抽象 為引數的 4 具體節點 5 物件結構 乙個例項的字段,或者使用聚集實現。注意的問題,適用性 1 存在乙個結構 節點的...