简介
访问者模式(Visitor Pattern):表示一个用于作用于某对象结构中的各个元素的操作。让用户在不改变各元素的类的前提下定义作用于这些元素的新操作。
- 为了以不同的方式操作复杂对象结构中的不同类型元素。
结构和实现
- 角色包括:
- 抽象访问者:为对象结构中的每一个具体元素类声明一个访问操作。
- 具体访问者:实现对每一具体元素的访问方法。
- 抽象元素:声明accept方法,接收访问者的访问操作,通常是抽象类和接口。
- 具体元素:实现accept方法,调用访问者的对应的访问方法。
- 对象结构:存放元素对象并提供遍历方法,可以使用组合模式实现。
- 访问者结构。
- 访问者模式有两个层次结构:访问者的层次、元素层次。
- 不同具体元素通过接收不同的具体访问者,以自身为参数,执行访问者中操作不同元素的方法,这称为双重分派机制。
public class ConcreteElementA implements Element
{
public void accept(Visitor visitor)
{
visitor.visit(this);
}
public void operationA()
{
//业务方法
}
}
实例
- 开发员工信息管理系统,员工包括正式工和临时工,每周人力资源部和财务部需要对员工数据进行汇总,包括工作时间、工资等。正式员工和临时工的工资和工作时间计算方法不一致。
- 财务部门的访问方法。
pubic class FADepartment extends Department
{
//实现财务部对全职员工的访问
public void visit(FulltimeEmployee employee)
{
int workTime = employee.getWorkTime();
double weekWage = employee.getWeeklyWage();
if(workTime > 40)
{
weekWage = weekWage + (workTime - 40) * 100;
}
else if(workTime < 40)
{
weekWage = weekWage - (40 - workTime) * 80;
if(weekWage < 0)
{
weekWage = 0;
}
}
System.out.println("正式员工" + employee.getName() + "实际工资为:" + weekWage + "元。");
}
//实现财务部对兼职员工的访问
public void visit(ParttimeEmployee employee)
{
int workTime = employee.getWorkTime();
double hourWage = employee.getHourWage();
System.out.println("临时工" + employee.getName() + "实际工资为:" + workTime * hourWage + "元。");
}
}
- HR部门的访问方法。
public class HRDepartment extends Department
{
//实现人力资源部对全职员工的访问
public void visit(FulltimeEmployee employee)
{
int workTime = employee.getWorkTime();
System.out.println("正式员工" + employee.getName() + "实际工作时间为:" + workTime + "小时。");
if(workTime > 40)
{
System.out.println("正式员工" + employee.getName() + "加班时间为:" + (workTime - 40) + "小时。");
}
else if(workTime < 40)
{
System.out.println("正式员工" + employee.getName() + "请假时间为:" + (40 - workTime) + "小时。");
}
}
//实现人力资源部对兼职员工的访问
public void visit(ParttimeEmployee employee)
{
int workTime = employee.getWorkTime();
System.out.println("临时工" + employee.getName() + "实际工作时间为:" + workTime + "小时。");
}
}
联用组合模式
- 元素可以使用组合模式表示树形结构。
优缺点和适用范围
- 优点:
- 增加新的访问操作容易。只需要增加一个新的访问者类,无需修改源码,符合开闭原则。
- 访问操作集中。访问操作集中在访问者中,而不是分散在元素中,类的职责清晰,有利于元素对象的复用。
- 缺点:
- 增加新的元素很难。需要在新的抽象访问者中增加一个新的操作,并在每一具体访问者中增加,违背开闭原则,且修改麻烦。
- 破坏封装性。访问者对象访问并且调用每一个元素对象的操作,对象又是必须暴露自己的内部状态和操作。
- 适用环境:
- 对象结构中包含多个类型的对象,希望针对不同类型提供不同的操作。
- 不希望在对象中增加访问操作,需要对象本身和访问操作分离。
- 元素对象的类型很少改变,但是需要经常增加新的操作。
jdk中的应用
- 提供对访问者模式的支持,javax.lang.model.element.Element和javax.lang.model.element.ElementVisitor分别对应抽象元素和抽象访问者。