访问者模式是设计模式中比较难理解的一个设计模式,理解这个模式之前,先说说开闭原则。
所谓开闭原则是指,当需求扩展变化的时候,尽量不要修改原来的类,模块等(闭),而是进行扩展(开)。对修改闭对扩展开(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);
这就是访问者模式的使用