意圖和簡介
意圖
使一個高層級的類方便地添加新的方法/操作/接口
- 擴(kuò)展性/表達(dá)式問題:對于任何一門編程語言而言,添加新子類與添加新方法之間是一個兩難的選擇(即若選擇使一個類易于添加新的操作那么這個類就難以去擴(kuò)展新的子類,而若這個類容易擴(kuò)展新的子類,那么就難以去添加新的操作)
何時使用
對于面向?qū)ο缶幊?,我們的依賴于抽象原則讓我們常常去擴(kuò)展一個抽象類的子類,而非它的方法。而有時我們會遇到這樣一種情況,它的子類是已經(jīng)確定的了。而它的方法/操作卻并非確定的(有很多)。
那么這個時候,我們可以使用訪問者模式將其轉(zhuǎn)換為易于擴(kuò)展新方法而非易于擴(kuò)展新子類的一個模式。
注:訪問者模式并沒有解決表達(dá)式問題,只是將問題的呈現(xiàn)變換了一種形式
使用的具體思路
????如果一個較高層級的類,它的子類是已知且確定的而操作是未知的,那么我們可以將其操作的具體實現(xiàn)從子類中抽取出來放到訪問者類中去實現(xiàn)。而它本身則通過accept方法調(diào)用訪問者類中相應(yīng)的visit()方法來實現(xiàn)將表達(dá)式問題從易于擴(kuò)展新的子類難添加新操作轉(zhuǎn)移為易于添加新操作而難以去擴(kuò)展新子類
可以拿生活中的事情做類比。
這個不知道操作有哪些種類的較高層次的類Receiver,某家的主人,這主人的種類是確定的,同時他們所擁有的房子也是確定的。有天客人Visitor去他家做客,visitor的種類并非是確定的,所以這些客人去某個主人家去說什么話做什么事也就是不知道的。而具體的客人說的具體的話和做的具體的事(即方法/操作)是根據(jù)不同的主人,該主人所擁有的房子以及這個visitor具體是誰來確定的(雙分派,即具體的操作由主客雙方來確定)。
具體示例
這里計算機(jī)對普通用戶開放的部件ComputerPart作為被訪問者(計算機(jī)對普通用戶開放的部件是確定和已知的)
具體的用戶操作作為訪問者,操作的種類這里實現(xiàn)了兩種,一種display,一種close,(展示和關(guān)閉)
1.被訪問者,抽象類ComputerPart
public interface ComputerPart
{
public void accept(ComputerPartVisitor computerPartVisitor);
}
2.被訪問者ComputerPart的幾個具體子類
public class Keyboard implements ComputerPart
{
@Override
public void accept(ComputerPartVisitor computerPartVisitor){
computerPartVisitor.visit(this);
}
}
public class Monitor implements ComputerPart
{
@Override
public void accept(ComputerPartVisitor computerPartVisitor){
computerPartVisitor.visit(this);
}
}
public class Mouse implements ComputerPart {
@Override
public void accept(ComputerPartVisitor computerPartVisitor) {
computerPartVisitor.visit(this);
}
}
public class Computer implements ComputerPart
{
ComputerPart[] parts;
public Computer(){
parts = new ComputerPart[]{
new Mouse(),new Keyboard(),new Monitor()
};
}
@Override
public void accept(ComputerPartVisitor computerPartVisitor) {
for (int i = 0; i < parts.length; i++) {
parts[i].accept(computerPartVisitor);
}
computerPartVisitor.visit(this);
}
}
3.訪問者抽象類
public interface ComputerPartVisitor
{
public void visit(Computer computer);
public void visit(Mouse mouse);
public void visit(Keyboard keyboard);
public void visit(Monitor monitor);
}
4.兩種訪問者的具體實現(xiàn)類(分別封裝了display操作和close操作)
public class ComputerPartDisplayVisitor implements ComputerPartVisitor {
@Override
public void visit(Computer computer) {
System.out.println("Displaying Computer.");
}
@Override
public void visit(Mouse mouse) {
System.out.println("Displaying Mouse.");
}
@Override
public void visit(Keyboard keyboard) {
System.out.println("Displaying Keyboard.");
}
@Override
public void visit(Monitor monitor) {
System.out.println("Displaying Monitor.");
}
}
public class ComputerPartCloseVisitor implements ComputerPartVisitor {
@Override
public void visit(Computer computer) {
System.out.println("closing Computer.");
}
@Override
public void visit(Mouse mouse) {
System.out.println("closing Mouse.");
}
@Override
public void visit(Keyboard keyboard) {
System.out.println("closing Keyboard.");
}
@Override
public void visit(Monitor monitor) {
System.out.println("closing Monitor.");
}
}
5.測試類
public class VisitorPatternDemo
{
public static void main(String[] args) {
ComputerPart computer = new Computer();
computer.accept(new ComputerPartDisplayVisitor());
ComputerPart monitor = new Monitor();
monitor.accept(new ComputerPartDisplayVisitor());
ComputerPart computer = new Computer();
computer.accept(new ComputerPartCloseVisitor());
}
}
綜上:操作對具體的計算機(jī)部件和操作的種類(display/close)的依賴構(gòu)成了訪問者模式中的職責(zé)雙分派。這樣就得到使用訪問者模式的一個場景:在遇到需要對一個類中操作的職責(zé)進(jìn)行雙分派的時候,我們可以考慮訪問者模式。