1.1概述 表示將一個作用於某對象結構中的各個元素的操作。它可以在不改變各個元素的類的前提下定義作用於這些元素的新操作。這就是訪問者模式的定義。 編寫類的時候,可能在該類中編寫了若幹個實例方法,該類的對象通過調用這些實例方法操作其成員變數表明所產生的行為。在某些設計中,可能需要定義作用於類的成員變數 ...
1.1概述
表示將一個作用於某對象結構中的各個元素的操作。它可以在不改變各個元素的類的前提下定義作用於這些元素的新操作。這就是訪問者模式的定義。
編寫類的時候,可能在該類中編寫了若幹個實例方法,該類的對象通過調用這些實例方法操作其成員變數表明所產生的行為。在某些設計中,可能需要定義作用於類的成員變數的新操作,而且這個新操作不應當由該類中的某個實例方法來承擔。
例如,有一個電錶(Ammeter)類,在電錶類中,electricAmount成員變數的值表示用電量,showElectricAmount()方法返回electricAmount變數的值來收取電費。現在的問題是:希望根據用電量來計算電費,即根據electricAmount變數的值來收取電費。顯然,不應該在Ammeter類中增加計算電費的方法(單表本身不能計算出電費)。在實際生活中,應當由物業部門的“計表員”觀察電錶的用電量,然後按著有關收費標準計算出電費。訪問者模式建議讓一個稱作訪問者的對象訪問Ammeter對象(電錶),以便定義作用於Ammeter對象上的操作。在訪問者模式中,“計表員”是AmmeterVisitor類的實例,稱作Ammeter類實例的訪問者,AmmeterVisitor類中有一個計算電費的方法:
void visit(Ammeter ammeter);
該方法的參數是Ammeter類的實例,因此只要將Ammeter類的實例傳遞給該方法的參數,AmmeterVisitor類的實例就可以計算出電費(PS:假設1度點0.88元):
double visit(Ammeter ammer){
charge = ammeter.showElectricAmount()*0.88;
return charge;
}
按著訪問者模式,應當在Ammeter類中增加一個接受訪問者的方法。Ammeter類中接受訪問者的方法可如下定義:
void accept(AmmeterVisitor v){
v.visit(this); //將自身傳遞給參數指定的訪問者
}
因此,一個Ammeter類的實例通過調用accept()方法,並向該方法傳遞一個訪問者,即AmmeterVisitor的實例,然後Ammeter類的實例再將自身傳遞給訪問者就可以知道自己需要交納多少電費了。Ammeter和AmmeterVisitor類的類圖如下圖一所示:
圖一:有關繳納電費關係類圖(PS:類圖畫的有點不規範,僅作參考哦)
Ammeter類有了接受訪問者的accept(AmmeterVisitor visitor)方法後,可以不改變Ammeter類就能定義作用於Ammeter對象的成員變數上的新操作,比如,可以讓accept(AmmeterVisitor visitor)的參數是AmmeterVisitor類的一個實例,該實例佈局根據Ammeter對象的成員變數計算出正常的電費,而且還可以計算超電量應繳納的額外電費。
1.2模式的結構
訪問者模式包括以下五種角色:
(1)抽象元素(Element):一個抽象類,該類定義了接受訪問者的accept操作。
(2)具體元素(Concrete Element):Element的子類。
(3)對象結構(Object Structure):一個集合,用於存放Element對象,提供遍歷它自己的方法。
(4)抽象訪問者(Visitor):一個介面,該介面定義操作對象(Concrete Element的實例)的方法。
(5)具體訪問者(Concrete Visitor):實現Visitor介面的類。
訪問者模式結構的類圖如下圖二所示:
圖二:訪問者模式的類圖(PS:類圖畫的有點不規範,僅作參考哦)
1.3訪問者模式的優點
(1)可以在不改變一個集合中元素類的情況下,增加新的施加於該元素上的新操作。
(2)可以將集合中各個元素的某些操作集中到訪問者中,不僅便於集合的維護,也有利於集合中元素的復用。
1.4適合使用訪問者模式的情景
(1)一個對象結構中,比如某個集合中,包含有很多對象,想對集合中對象增加新的操作。
(2)需要對集合中的對象進行很多不同並且不相關的操作,而又不想修改對象的類,就可以使用訪問者模式。訪問者模式可以在Visitor類中集中定義一些關於集合中對象的操作。