定义
表示一个作用于某对象结构中的各元素的操作。它使你可以在不改变各元素类的前提下定义作用于这些元素的新操作。
UML
优点
- 符合单一职责原则:凡是适用访问者模式的场景中,元素类中需要封装在访问者中的操作必定是与元素类本身关系不大且是易变的操作,使用访问者模式一方面符合单一职责原则,另一方面,因为被封装的操作通常来说都是易变的,所以当发生变化时,就可以在不改变元素类本身的前提下,实现对变化部分的扩展;
- 扩展性良好:元素类可以通过接受不同的访问者来实现对不同操作的扩展;
- 允许你对组合结构加入新的操作,无需改变结构本身;
- 想要加入新的操作相对容易;
- 访问者所进行的操作,其代码是集中在一起的。
缺点
- 会打破组合类的封装;
- 因为游走的功能牵涉其中,随意对组合结构的改变就更加困难。
应用场景
- 一个对象结构包含很多类对象,它们有不同的接口,而你想对这些对象实施一些依赖于其具体类的操作;
- 需要对一个对象结构中的对象进行很多不同的并且不相关的操作,而你想避免让这些操作“污染”这些对象的类。Visitor模式使得你可以将相关的操作集中起来定义在一个类中;
- 当该对象结构被很多应用共享时,用Visitor模式让每个应用仅包含需要用到的操作;
- 定义对象结构的类很少改变,但经常需要在此结构上定义新的操作。改变对象结构类需要重定义对所有访问者的接口,这可能需要很大的代价。如果对象结构类经常改变,那么可能还是在这些类中定义这些操作较好。
示例
通过访问者来访问不同对象并打印对应访问者刚兴趣的数据出来。
Java
1 import java.util.ArrayList; 2 import java.util.List; 3 4 public class Main 5 { 6 public static void main(String[] args) 7 { 8 List<Employee> list = new ArrayList<>(); 9 10 CommonEmployee zhangSan = new CommonEmployee(); 11 zhangSan.setName("张三"); 12 zhangSan.setSex(Employee.MALE); 13 zhangSan.setSalary(5000); 14 zhangSan.setJob("苦逼的码农"); 15 list.add(zhangSan); 16 17 CommonEmployee liSi = new CommonEmployee(); 18 liSi.setName("李四"); 19 liSi.setSex(Employee.FEMALE); 20 liSi.setSalary(20000); 21 liSi.setJob("公司里唯一的程序媛"); 22 list.add(liSi); 23 24 Manager wangWu = new Manager(); 25 wangWu.setName("王五"); 26 wangWu.setSex(Employee.MALE); 27 wangWu.setSalary(66000); 28 wangWu.setPerformance("业绩基本为负值,不过每次马屁都拍得老板很飘!"); 29 list.add(wangWu); 30 31 for (Employee em : list) 32 { 33 em.accept(new Visitor()); 34 } 35 } 36 37 /** 38 * 访问者接口 39 */ 40 public interface IVisitor 41 { 42 /** 43 * 访问普通员工 44 */ 45 void visit(CommonEmployee commonEmployee); 46 47 /** 48 * 访问经理 49 */ 50 void visit(Manager manager); 51 } 52 53 /** 54 * 访问者对象 55 */ 56 public static class Visitor implements IVisitor 57 { 58 @Override 59 public void visit(CommonEmployee commonEmployee) 60 { 61 System.out.println(getCommonEmployee(commonEmployee)); 62 } 63 64 @Override 65 public void visit(Manager manager) 66 { 67 System.out.println(getManagerInfo(manager)); 68 } 69 70 private String getBasicInfo(Employee employee) 71 { 72 String info = "姓名:" + employee.getName() + " "; 73 info += "性别:" + (employee.getSex() == Employee.MALE ? "男" : "女") + " "; 74 info += "薪水:" + employee.getSalary() + " "; 75 return info; 76 } 77 78 private String getCommonEmployee(CommonEmployee commonEmployee) 79 { 80 String basicInfo = getBasicInfo(commonEmployee); 81 String otherInfo = "工作:" + commonEmployee.getJob(); 82 return basicInfo + otherInfo; 83 } 84 85 private String getManagerInfo(Manager manager) 86 { 87 String basicInfo = getBasicInfo(manager); 88 String otherInfo = "业绩:" + manager.getPerformance(); 89 return basicInfo + otherInfo; 90 } 91 } 92 93 /** 94 * 员工基类 95 */ 96 public static abstract class Employee 97 { 98 public final static int MALE = 0; 99 100 public final static int FEMALE = 1; 101 102 private String name; 103 private int sex; 104 private int salary; 105 106 public String getName() 107 { 108 return name; 109 } 110 111 public void setName(String name) 112 { 113 this.name = name; 114 } 115 116 public int getSex() 117 { 118 return sex; 119 } 120 121 public void setSex(int sex) 122 { 123 this.sex = sex; 124 } 125 126 public int getSalary() 127 { 128 return salary; 129 } 130 131 public void setSalary(int salary) 132 { 133 this.salary = salary; 134 } 135 136 /** 137 * 接受访问者访问 138 */ 139 public abstract void accept(IVisitor visitor); 140 } 141 142 /** 143 * 普通员工 144 */ 145 public static class CommonEmployee extends Employee 146 { 147 private String job; 148 149 public String getJob() 150 { 151 return job; 152 } 153 154 public void setJob(String job) 155 { 156 this.job = job; 157 } 158 159 @Override 160 public void accept(IVisitor visitor) 161 { 162 visitor.visit(this); 163 } 164 } 165 166 /** 167 * 经理 168 */ 169 public static class Manager extends Employee 170 { 171 private String performance; 172 173 public String getPerformance() 174 { 175 return performance; 176 } 177 178 public void setPerformance(String performance) 179 { 180 this.performance = performance; 181 } 182 183 @Override 184 public void accept(IVisitor visitor) 185 { 186 visitor.visit(this); 187 } 188 } 189 }