1.定义
封装一些作用于某种数据结构中的各个元素的操作,它可以在不改变这个数据结构的前提下定义作用于这些元素的新操作。
2.使用场景
1.对象结构比较稳定,但经常需要在此对象结构上定义新的操作。
2.需要一个对象结构中的对象进行很多不同的并且不相关的操作,而需要避免这些操作污染这些对象类,也不希望在增加新操作时修改这些类。
3.简单实现
公司对员工需要绩效考核,简单的把员工分为工程师和经理,评定员工的分别为CEO和CTO,假定CTO只关注工程师的代码量,经理的新产品数量,CEO只关注工程师的KPI和经理的KPI以及新产品数量。CEO和CTO对不同的员工关注点不一样,就需要对不同的员工类型进行不同的处理,这里就可以用访问者模式。
//定义访问者接口 interface Visitor{ //访问工程师类型 public void visitor(Engineer engineer); //访问经理类型 public void visitor(ProjectManager manager); } //CEO class CEO implements Visitor{ @Override public void visitor(Engineer engineer) { //CEO只关注工程师的KPI System.out.println("工程师:" + engineer.name + " KPI: "+ engineer.KPI); } @Override public void visitor(ProjectManager manager) { //CEO只关注经理的kpi和产品数量 System.out.println("经理:" + manager.name + " KPI:" + manager.KPI + " 产品数量:" + manager.getProducts()); } } //CTO class CTO implements Visitor{ @Override public void visitor(Engineer engineer) { //CTO只关注工程师的代码行数 System.out.println("工程师:" + engineer.name + " 代码行数:"+ engineer.getCodeLines()); } @Override public void visitor(ProjectManager manager) { //CTO关注经理的产品数量 System.out.println("经理:" + manager.name + " 产品数量:" + manager.getProducts()); } } //员工基类 abstract class Staff{ public String name; public int KPI; public Staff(String myname){ name = myname; KPI = new Random().nextInt(10); } //接收Visitor的访问 public abstract void accept(Visitor visitor); } //工程师 class Engineer extends Staff{ public Engineer(String name) { super(name); } public int getCodeLines(){ //获取今年代码数量 return new Random().nextInt(10*10000); } @Override public void accept(Visitor visitor) { visitor.visitor(this); } } //经理类 class ProjectManager extends Staff{ private int products; //产品数量 public ProjectManager(String name,int products) { super(name); this.products = products; } public int getProducts(){ return products; } @Override public void accept(Visitor visitor) { visitor.visitor(this); } } //生成一个业务报表 class Report{ List<Staff> staff = new LinkedList<Staff>(); public Report() { //简单构建一些员工 staff.add(new ProjectManager("王经理",3)); staff.add(new ProjectManager("胡经理",2)); staff.add(new Engineer("赵工")); staff.add(new Engineer("李工")); staff.add(new Engineer("钱工")); staff.add(new Engineer("孙工")); } //为访问者展示报表 public void showReport(Visitor visitor){ for (Staff s:staff){ s.accept(visitor); } } } public class VisitorMode { public static void main(String[] args){ //构建报表 Report report = new Report(); System.out.println("-------CEO看的报表-------"); report.showReport(new CEO()); System.out.println("-------CTO看的报表-------"); report.showReport(new CTO()); } }
输出:
4.小结
大多数情况下,你并不需要使用访问者模式,但是当你一旦需要使用它时,那你就是真的需要它。
优点:
1.各个角色职责分离,符合单一职责原则
2.拓展性高,灵活性好
3.操作与数据结构解耦,使得操作集合可以独立变化。
缺点:
1.具体元素对访问者公布细节,违反迪米特原则;
2.具体元素修改导致修改成本变大
3.依赖了具体的类,没有依赖抽象,违反依赖倒置原则。