訪問(wèn)者模式提供了一種方法,將算法和數(shù)據(jù)結(jié)構(gòu)分離逾苫。假設(shè)我們需要對(duì)一個(gè)數(shù)據(jù)結(jié)構(gòu)進(jìn)行不同的操作卿城,就可以考慮使用訪問(wèn)者模式。訪問(wèn)者模式的要點(diǎn)在于铅搓,需要一個(gè)訪問(wèn)者接口瑟押,提供了一些重載方法來(lái)訪問(wèn)具體對(duì)象。對(duì)于每個(gè)具體對(duì)象星掰,又提供了一個(gè)accept方法來(lái)回調(diào)訪問(wèn)者多望。
首先來(lái)看看訪問(wèn)者嫩舟。
public interface Visitor {
void visit(House house);
void visit(Kitchen kitchen);
void visit(LivingRoom livingRoom);
void visit(BedRoom bedRoom);
}
class HouseVisitor implements Visitor {
public void visit(House house) {
System.out.println("訪問(wèn)了房子");
}
public void visit(BedRoom bedRoom) {
System.out.println("訪問(wèn)了臥室");
}
public void visit(LivingRoom livingRoom) {
System.out.println("訪問(wèn)了客廳");
}
public void visit(Kitchen kitchen) {
System.out.println("訪問(wèn)了廚房");
}
}
然后是要訪問(wèn)的對(duì)象,這里是一間屋子怀偷。
public class House {
private LivingRoom livingRoom;
private Kitchen kitchen;
private BedRoom bedRoom;
public House() {
livingRoom = new LivingRoom();
kitchen = new Kitchen();
bedRoom = new BedRoom();
}
public void accept(Visitor visitor) {
visitor.visit(this);
livingRoom.accept(visitor);
bedRoom.accept(visitor);
kitchen.accept(visitor);
}
}
class LivingRoom {
public void accept(Visitor visitor) {
visitor.visit(this);
}
}
class Kitchen {
public void accept(Visitor visitor) {
visitor.visit(this);
}
}
class BedRoom {
public void accept(Visitor visitor) {
visitor.visit(this);
}
}
然后客戶端就可以簡(jiǎn)單的訪問(wèn)屋子了家厌。
public void run() {
Visitor visitor = new HouseVisitor();
House house = new House();
visitor.visit(house);
}
這就是訪問(wèn)者模式了∽倒ぃ可能會(huì)同學(xué)會(huì)有疑問(wèn)饭于,為什么我要這么寫?如果讓屋子對(duì)象層次全部都實(shí)現(xiàn)Visitor接口维蒙,然后客戶端直接調(diào)用這些visit方法不是也可以嗎掰吕?一開始我也有這個(gè)疑問(wèn),后來(lái)看了知乎輪子哥的一篇文章ParserGen生成預(yù)定義好的各種visitor颅痊,感覺(jué)茅塞頓開殖熟。
其實(shí)Visitor模式講的就是在不需要擴(kuò)充新的子類的時(shí)候,如何添加新的虛函數(shù)而不需要修改原有代碼斑响。當(dāng)然虛函數(shù)也有它的好處菱属,就是添加新的子類的時(shí)候不需要修改原有代碼。所以看你的業(yè)務(wù)邏輯恋捆,到底是添加新子類多照皆,還是添加新虛函數(shù)多,從而選擇要不要把程序?qū)懗苫赩isitor模式的樣子沸停。
對(duì)于編譯器來(lái)說(shuō),整個(gè)處理流程那么復(fù)雜昭卓,所以等于需要經(jīng)常添加虛函數(shù)愤钾,因此就都把本來(lái)是虛函數(shù)的東西改成了各種Visitor。這個(gè)時(shí)候候醒,如果你修改了語(yǔ)法能颁,那么每一個(gè)Visitor都會(huì)曝出語(yǔ)法錯(cuò)誤,所以這等于變相通知你所有需要修改的東西在哪里——如果你能堅(jiān)持不因?yàn)橥祽卸褂胐ynamic_cast的話倒淫。
所謂設(shè)計(jì)模式伙菊,都需要在特定的環(huán)境中才有用。所以現(xiàn)在我們已經(jīng)了解了什么情況下應(yīng)該使用訪問(wèn)者模式敌土。假如接口中的方法固定镜硕,但是需要添加新的實(shí)現(xiàn)類,那么就使用普通的繼承方式返干。如果接口方法經(jīng)常變動(dòng)兴枯,就可以把接口改寫為訪問(wèn)者。