让自己的内心藏着一条巨龙,既是一种苦刑,也是一种乐趣——雨果
 
今天跟着一个网站 学了学访问者模式
简单来说,如果我们要在不改动现有逻辑的情况下对类进行增强,则可以使用访问者模式
真实世界类比 
优秀的保险代理人总能为不同类型的团体提供不同的保单。
假如有这样一位非常希望赢得新客户的资深保险代理人。 他可以拜访街区中的每栋楼, 尝试向每个路人推销保险。 所以, 根据大楼内组织类型的不同, 他可以提供专门的保单:
如果建筑是居民楼, 他会推销医疗保险。
我们这里有多栋建筑,但我们不能在建筑类中写推销保险的代码,并且尽可能考虑未来拓展性
我们尝试用访问者模式去完成这样一个案例:
建筑接口 package  com.ruben.vistor.example.Insurance;public  interface  Building           String getName ()  ;          void  arrived ()           void  beVisited (Person person)  } 
这个建筑接口中有三个函数,前面两个函数是我们需要具体执行的函数,第三个函数则是提供一个入口,让建筑能够被人访问Person类,对应人Building接口,写出居民楼、银行、咖啡厅的代码
居民楼 package  com.ruben.vistor.example.Insurance;public  class  ResidentialBuilding  implements  Building      private  String name;     public  ResidentialBuilding (String name)           this .name = name;     }          @Override      public  String getName ()           return  name;     }          @Override      public  void  arrived ()           System.out.println("到达"  + getName());     }     public  void  setName (String name)           this .name = name;     }          @Override      public  void  beVisited (Person person)           person.visit(this );     } } 
银行 package  com.ruben.vistor.example.Insurance;public  class  Bank  implements  Building      private  String name;     public  Bank (String name)           this .name = name;     }          @Override      public  String getName ()           return  name;     }          @Override      public  void  arrived ()           System.out.println("到达"  + getName());     }     public  void  setName (String name)           this .name = name;     }          @Override      public  void  beVisited (Person person)           person.visit(this );     } } 
咖啡厅 package  com.ruben.vistor.example.Insurance;public  class  CoffeeShop  implements  Building      private  String name;     public  CoffeeShop (String name)           this .name = name;     }          @Override      public  String getName ()           return  name;     }          @Override      public  void  arrived ()           System.out.println("到达"  + getName());     }     public  void  setName (String name)           this .name = name;     }          @Override      public  void  beVisited (Person person)           person.visit(this );     } } 
然后是我们的Person接口,其中有对应访问三个建筑的方法
package  com.ruben.vistor.example.Insurance;public  interface  Person           void  visit (ResidentialBuilding building)           void  visit (Bank building)           void  visit (CoffeeShop building)  } 
Person对应的实现类接下来就是我们的保险推销员了,写上具体增强逻辑
package  com.ruben.vistor.example.Insurance;public  class  InsuranceSeller  implements  Person           public  void  visit (Building building)           System.out.println("开始去"  + building.getName() + "推销保险!" );         building.beVisited(this );     }          @Override      public  void  visit (ResidentialBuilding building)           building.arrived();         System.out.println("开始推销医疗保险" );     }          @Override      public  void  visit (Bank building)           building.arrived();         System.out.println("开始推销失窃保险" );     }          @Override      public  void  visit (CoffeeShop building)           building.arrived();         System.out.println("开始推销火灾、洪水保险" );     } } 
这里第一个函数通过上面对Building中第三个入口函数的调用,则调用到对应具体建筑的beVisited方法,其中又调用了Person中的visit方法,注意这里调用的就不是我们下面第一个函数了,而是对应具体实现类参数的那一个visit方法,如银行,则调用的是visit(Bank building)
最后则是调用 package  com.ruben.vistor.example.Insurance;public  class  SellInsurance      public  static  void  main (String[] args)           InsuranceSeller insuranceSeller = new  InsuranceSeller();         Building residentialBuilding = new  ResidentialBuilding("碧桂园" );         residentialBuilding.beVisited(insuranceSeller);         Building bank = new  Bank("农业银行" );         bank.beVisited(insuranceSeller);         Building coffeeShop = new  CoffeeShop("瑞幸咖啡" );         coffeeShop.beVisited(insuranceSeller);     } } 
可以看到我这里成功让推销员对不同的建筑执行不同的逻辑,虽然是不同的子类,但我们传入的都是父类Building,但保险推销员能根据不同的子类执行不同的逻辑了
访问者模式优缺点 优点:
缺点:Person、保险推销员和外卖员中都新增这个建筑)