访问者模式,主要的作用就是把数据结构和针对数据结构上的操作进行解耦,适用于数据结构稳定,但是针对数据的操作容易变化的场景,访问者模式,改变操作数据的方法容易,但是改变数据结构困难,如果数据结构经常变化,则不能使用此模式
先来确定一下访问者模式的组成
被访问者接口:提供接收访问方法
被访问者:接收访问,将自己的提供给访问者,自己的结构不易变化
访问者接口:提供不同的访问方法
访问者:访问数据,对针对数据的结构有不同的造作。
我们还是来举个栗子:
每个员工都有工龄和工资,公司按照工龄来计算工资,社保局根据工资和工龄来计算是否符合退休条件以及退休工资
这里抽象一个员工接口,接收访问
具体一个人实现接口,包含姓名,工龄,工资
再抽象一个机构接口,可以访问员工的信息
公司和社保局实现机构接口,处理自己的逻辑。
/**
* @author: hx
* @Time: 2019/5/23
* @Description: Org
*/
public interface Org {
void visit(Person person);
}
/**
* @author: hx
* @Time: 2019/5/23
* @Description: employee
*/
public interface employee {
void accept(Org org);
}
/**
* @author: hx
* @Time: 2019/5/23
* @Description: Person
*/
public class Person implements employee {
private String name;
private int workingAge;
private double salary;
public Person(String name, int workingAge, double salary) {
this.name = name;
this.workingAge = workingAge;
this.salary = salary;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getWorkingAge() {
return workingAge;
}
public void setWorkingAge(int workingAge) {
this.workingAge = workingAge;
}
public double getSalary() {
return salary;
}
public void setSalary(double salary) {
this.salary = salary;
}
@Override
public void accept(Org org) {
org.visit(this);
}
}
/**
* @author: hx
* @Time: 2019/5/23
* @Description: Company
*/
public class Company implements Org {
@Override
public void visit(Person person) {
if (person.getWorkingAge() > 5){
System.out.println(person.getName()+"当前薪资"+person.getSalary()+",涨薪100");
}else if (person.getWorkingAge() > 10){
System.out.println(person.getName()+"当前薪资"+person.getSalary()+",涨薪500");
}else{
System.out.println(person.getName()+"当前薪资"+person.getSalary()+",不涨薪");
}
}
}
/**
* @author: hx
* @Time: 2019/5/23
* @Description: SocialSecurityBureau
*/
public class SocialSecurityBureau implements Org {
@Override
public void visit(Person person) {
if (person.getWorkingAge() < 15) {
System.out.println(person.getName()+"不符合退休条件");
}else {
System.out.println(person.getName()+"退休工资为:"+(person.getWorkingAge()*10 + person.getSalary()*0.8));
}
}
}
来看一下怎么访问
public static void main(String[] args){
Person person1 = new Person("小明",3,3000D);
Person person2 = new Person("小红",6,5000D);
Person person3 = new Person("小张",11,8000D);
Person person4 = new Person("小王",16,10000D);
person1.accept(new Company());
person1.accept(new SocialSecurityBureau());
person2.accept(new Company());
person2.accept(new SocialSecurityBureau());
person3.accept(new Company());
person3.accept(new SocialSecurityBureau());
person4.accept(new Company());
person4.accept(new SocialSecurityBureau());
}
输出结果:
小明当前薪资3000.0,不涨薪
小明不符合退休条件
小红当前薪资5000.0,涨薪100
小红不符合退休条件
小张当前薪资8000.0,涨薪100
小张不符合退休条件
小王当前薪资10000.0,涨薪100
小王退休工资为:8160.0
功能已经实现,但是可以看到,调用的时候特别麻烦,也可以看到,在实际调用的时候,组织的实现类不能调用接口,所以,访问者模式是不符合依赖倒转原则的。所以才会有对数据结构的稳定性有要求。
上面的调用其实也可以一个管理类中集中管理起来
/**
* @author: hx
* @Time: 2019/5/23
* @Description: People
*/
public class People {
private List mPeople = new ArrayList<>();
public void addPerson(Person person){
mPeople.add(person);
}
public void accept(Org org){
for (Person person : mPeople){
person.accept(org);
}
}
}
再看一下调用
public static void main(String[] args){
Person person1 = new Person("小明",3,3000D);
Person person2 = new Person("小红",6,5000D);
Person person3 = new Person("小张",11,8000D);
Person person4 = new Person("小王",16,10000D);
People people = new People();
people.addPerson(person1);
people.addPerson(person2);
people.addPerson(person3);
people.addPerson(person4);
people.accept(new Company());
people.accept(new SocialSecurityBureau());
}
输出结果:
小明当前薪资3000.0,不涨薪
小红当前薪资5000.0,涨薪100
小张当前薪资8000.0,涨薪100
小王当前薪资10000.0,涨薪100
小明不符合退休条件
小红不符合退休条件
小张不符合退休条件
小王退休工资为:8160.0
比第一种稍稍好一点
优点
增加新的访问操作十分方便
每个访问者类的职责更加清晰
将有关元素对象的访问行为集中到一个访问者对象中,而不是分散在一个个的元素类中,集中管理
缺点
增加新的元素类很困难,违背了开闭原则
访问者访问的是实现类而不是接口,违背了依赖倒转原则
应用场景
一个对象结构包含多个类型的对象,对这些对象的造作依赖具体实现。 不同的类型可以有不同的访问操作
数据结构对象结构不会改变,但经常需要在此对象结构上定义新的操作。