本文介绍访问者模式的概念和应用。
基本思想和原则
封装一些作用于某种数据结构中的各元素的操作,它可以在不改变数据结构的前提下定义作用于这些元素的新操作。
动机
如果我们要获取很多类的不同对象的信息时,可以考虑使用访问者模式。这可以将访问类对象信息这个操作和类本身分离。
实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165
| public abstract class Staff { private String name; private int age; private int salary;
public Staff(String name, int age, int salary) { this.name = name; this.age = age; this.salary = salary; }
public String getName() { return this.name; }
public void setName(String name) { this.name = name; }
public int getAge() { return this.age; }
public void setAge(int age) { this.age = age; }
public int getSalary() { return this.salary; }
public void setSalary(int salary) { this.salary = salary; }
public abstract void accept(IVisitor visitor); }
public class Empolyee extends Staff { private String job;
public Empolyee(String name, int age, int salary) { super(name, age, salary); }
public String getJob() { return this.job; }
public void setJob(String job) { this.job = job; }
public void accept(IVisitor visitor) { visitor.visit(this); } }
public class Manager extends Staff { private int performance;
public Manager(String name, int age, int salary) { super(name, age, salary); }
public int getPerformance() { return this.performance; }
public void setPerformance(int performance) { this.performance = performance; }
public void accept(IVisitor visitor) { visitor.visit(this); } }
public interface IVisitor { public void visit(Empolyee empolyee); public void visit(Manager manager); }
private String info = ""; @Override public void visit(Empolyee empolyee) { this.info += this.getBasicInfo(empolyee) + " " + this.getEmpolyeeJob(empolyee) + "\n"; }
@Override public void visit(Manager manager) { this.info += this.getBasicInfo(manager) + " " + this.getManagerPerformance(manager) + "\n"; }
private String getBasicInfo(Staff staff) { return staff.getName() + " " + staff.getAge() + " " + staff.getSalary(); }
private String getEmpolyeeJob(Empolyee empolyee) { return empolyee.getJob(); }
private int getManagerPerformance(Manager manager) { return manager.getPerformance(); }
public void showStaffInfo() { System.out.println(this.info); } }
public class BonusVisitor implements IVisitor { private final static int EMPOLYEE_COEFFICIENT = 2; private final static int MANAGER_COEFFICIENT = 4; private int totalBonus = 0;
@Override public void visit(Empolyee empolyee) { this.totalBonus += empolyee.getSalary() * EMPOLYEE_COEFFICIENT; }
@Override public void visit(Manager manager) { this.totalBonus += manager.getSalary() * MANAGER_COEFFICIENT; }
public void showTotalBonus() { System.out.println("所有人的奖金总和是: " + this.totalBonus); } }
public class Test { public static void main(String[] args) { InfoVisitor infoVisitor = new InfoVisitor(); BonusVisitor bonusVisitor = new BonusVisitor(); for (Staff staff:getStaffs()) { staff.accept(infoVisitor); staff.accept(bonusVisitor); }
infoVisitor.showStaffInfo(); bonusVisitor.showTotalBonus(); }
private static ArrayList<Staff> getStaffs() { ArrayList<Staff> staffs = new ArrayList<Staff>();
Empolyee empolyee1 = new Empolyee("Jack", 30, 8000); Empolyee empolyee2 = new Empolyee("Bob", 23, 4000); Empolyee empolyee3 = new Empolyee("Jane", 33, 9000); Manager manager1 = new Manager("John", 50, 20000);
empolyee1.setJob("Sale"); empolyee2.setJob("Engineer"); empolyee3.setJob("Accounting"); manager1.setPerformance(100000);
staffs.add(empolyee1); staffs.add(empolyee2); staffs.add(empolyee3); staffs.add(manager1);
return staffs; } }
|
输出如下:
1 2 3 4 5 6
| Jack 30 8000 Sale Bob 23 4000 Engineer Jane 33 9000 Accounting John 50 20000 100000
所有人的奖金总和是: 122000
|
IVisitor
声明了访问者的抽象接口,有两个具体的实现类:InfoVisitor
和BonusVisitor
,分别负责获取雇员的个人信息和计算奖金,这两个类的职责不同,一个打印信息,一个计算奖金,所以分为两个访问者类来实现没什么问题,实际开发中也提倡这么做。
优点
访问者模式符合单一职责原则,被访问者和访问者都可以各自独立发展,互不干扰。扩展性也不错,当需要增加新的访问需求时,只需要增加新的访问者实现类即可。
缺点
访问者模式必须了解一个具体类的细节,者违反了迪米特法则。另外有一种情况的扩展比较困难,当我在具体类中加入新的属性时,就需要修改访问者类,如果访问者类比较多,修改量会很大。访问者模式没有依赖抽象,而是依赖具体,这也违反了依赖倒置原则。