訪問者模式是設計模式中比較難理解的一個設計模式,理解這個模式之前,先說說開閉原則。
所謂開閉原則是指,當需求擴展變化的時候,儘量不要修改原來的類,模塊等(閉),而是進行擴展(開)。對修改閉對擴展開(Software entities should be open for extension,but closed for modification)
java代碼中的一個慣例:一般在繼承的情況下會使用父類或者接口名來聲明類變量,以便有更好擴展性。
當使用父類名稱聲明變量的時候,碰上重載的情況下就會考慮出現如下情況:
重載一般是靜態綁定,即根據聲明類型綁定方法;而我們使用一般是會父類名進行聲明的,這樣就會出現問題。如下:
public class Father{
……
}
public class Son extends Father{
……
}
public class Business{
public void play(Father f){
System.out.println("Father is playing");
}
public void play(Son s){
System.out.println("Son is playing");
}
}
public class Test{
public static void main(String []args){
private Father son = new Son();
Business bs = new Business();
bs.play(son);
}
}
如上不會如願的輸出Son is playing。而是上者。此時必須在Business類下加上類型判斷才能輸出正確的類型。即如下修改片段:
public void play(Father f){
if(f instanceof Son){
play((Son) f);
}else{
System.out.println("Father is playing");
}
}
試想,在play(Father f)方法中要進行instanceof判斷,如果類型子類多的話,會變得很難維護。
根據開閉原則,如果Father產生新的子類的情況下,會很大程度的修改Business類中的方法,這很不利於程序的維護升級。
這個時候,訪問者模式就會使用到。如下,在Father類和Son類中都增加一個方法,如下:
public void accept(Business b){
b.play(this);
}
並且修改測試類爲:
public class Test{
public static void main(String []args){
private Father son = new Son();
Business bs = new Business();
son.accept(bs);
}
}
//如果產生新子類的時候,對代碼影響也不會太大,實現此功能比較關鍵的地方在於下面的<span style="font-family: Arial, Helvetica, sans-serif;">this對象</span>
b.play(this);
這就是訪問者模式的使用