概述
访问者模式可以将某种固定结构的数据类型 在不改变数据结构的前提下 实现不同的访问方法 起到不改变数据结构呈现不同内容的作用
关系类图
主要思想是被访问者通过开放接口 允许访问者访问自身内容
同时访问者可以通过调用接口拿到被访问者的数据 然后进行自己想要的操作
代码实现
被访问者
被访问者提供方法让访问者可以访问自己本身
public abstract class Employee {
String name;
int kpi;
int age;
public Employee(String name) {
this.name = name;
kpi = new Random().nextInt(4);
age = new Random().nextInt(40);
}
public abstract void accept(EmployeeVisitor employeeVisitor);
}
public class Engineer extends Employee{
public Engineer(String name) {
super(name);
}
@Override
public void accept(EmployeeVisitor employeeVisitor) {
employeeVisitor.visit(this);
}
// 工程师考核指标是 工作年限
public int getWorkAge(){
return this.age;
}
}
public class Manager extends Employee{
public Manager(String name) {
super(name);
}
@Override
public void accept(EmployeeVisitor employeeVisitor) {
employeeVisitor.visit(this);
}
// 经理的考核指标是产品数量
public int getProduct(){
return new Random().nextInt(10);
}
}
访问者
访问者接口提供获得访问者信息的接口 访问者和被访问者是互相依赖的关系
public interface EmployeeVisitor {
void visit(Engineer engineer);
void visit(Manager manager);
}
public class CEO implements EmployeeVisitor{
@Override
public void visit(Engineer engineer) {
System.out.println(engineer.name + "的工作年限是:"+engineer.getWorkAge());
}
@Override
public void visit(Manager manager) {
System.out.println(manager.name + "的产品数量是:"+manager.getProduct());
}
}
public class CTO implements EmployeeVisitor{
@Override
public void visit(Engineer engineer) {
System.out.println(engineer.name + "的KPI是:"+engineer.kpi);
}
@Override
public void visit(Manager manager) {
System.out.println(manager.name + "的KPI是:"+manager.kpi);
}
}
数据源
public class Data {
private List<Employee> list = new ArrayList<>();
{
list.add(new Engineer("工程师A"));
list.add(new Engineer("工程师B"));
list.add(new Engineer("工程师C"));
list.add(new Engineer("工程师D"));
list.add(new Manager("经理A"));
list.add(new Manager("经理B"));
list.add(new Manager("经理C"));
list.add(new Manager("经理D"));
}
public void accpt(EmployeeVisitor employeeVisitor){
for (Employee employee : list) {
employee.accept(employeeVisitor);
}
}
}
客户端
public class App {
public static void main(String[] args) {
Data data = new Data();
System.out.println("CEO访问");
data.accpt(new CEO());
System.out.println("====================");
System.out.println("CTO访问");
data.accpt(new CTO());
}
}
====结果
CEO访问
工程师A的工作年限是:29
工程师B的工作年限是:13
工程师C的工作年限是:8
工程师D的工作年限是:13
经理A的产品数量是:4
经理B的产品数量是:8
经理C的产品数量是:3
经理D的产品数量是:5
====================
CTO访问
工程师A的KPI是:3
工程师B的KPI是:3
工程师C的KPI是:3
工程师D的KPI是:3
经理A的KPI是:2
经理B的KPI是:3
经理C的KPI是:2
经理D的KPI是:3
优点
- 扩展性好。能够在不修改对象结构中的元素的情况下,为对象结构中的元素添加新的功能
比如本文如果想加一个访问者或者是加一个员工的类 都不需要改变本身内容 - 复用性好。可以通过访问者来定义整个对象结构通用的功能,从而提高系统的复用程度
- 灵活性好。访问者模式将数据结构与作用于结构上的操作解耦
- 符合单一职责原则。访问者模式把相关的行为封装在一起,构成一个访问者,使每一个访问者的功能都比较单一
缺点
- 增加新的元素类很困难。在访问者模式中,每增加一个新的元素类,都要在每一个具体访问者类中增加相应的具体操作,这违背了“开闭原则
- 破坏封装。访问者模式中具体元素对访问者公布细节,这破坏了对象的封装性
- 违反了依赖倒置原则。访问者模式依赖了具体类,而没有依赖抽象类